re PR target/51244 ([SH] Inefficient conditional branch and code around T bit)

PR target/51244
	* config/sh/predicates.md (t_reg_operand, negt_reg_operand): New
	predicates.
	* config/sh/sh-protos.h (get_t_reg_rtx): New prototype.
	* config/sh/sh.c (get_t_reg_rtx): New function.  Use it when invoking
	gen_branch_true and gen_branch_false.
	* config/sh/sh.md: Use get_t_reg_rtx when invoking gen_branch_true and
	gen_branch_false.
	(branch_true, branch_false): Use t_reg_operand predicate.
	(*branch_true, *branch_false): Delete.
	(movt): Use t_reg_operand predicate.
	(*negnegt): Use negt_reg_operand predicate and fold little and big
	endian variants.
	(*movtt): Use t_reg_operand and fold little and big endian variants.
	(*movt_qi): Delete.

	PR target/51244
	* gcc.target/sh/pr51244-1.c: Check that movt insn is not generated.

From-SVN: r189177
This commit is contained in:
Oleg Endo 2012-07-02 19:23:56 +00:00
parent 73a1569582
commit f031c3441f
7 changed files with 98 additions and 107 deletions

View File

@ -1,3 +1,21 @@
2012-07-02 Oleg Endo <olegendo@gcc.gnu.org>
PR target/51244
* config/sh/predicates.md (t_reg_operand, negt_reg_operand): New
predicates.
* config/sh/sh-protos.h (get_t_reg_rtx): New prototype.
* config/sh/sh.c (get_t_reg_rtx): New function. Use it when invoking
gen_branch_true and gen_branch_false.
* config/sh/sh.md: Use get_t_reg_rtx when invoking gen_branch_true and
gen_branch_false.
(branch_true, branch_false): Use t_reg_operand predicate.
(*branch_true, *branch_false): Delete.
(movt): Use t_reg_operand predicate.
(*negnegt): Use negt_reg_operand predicate and fold little and big
endian variants.
(*movtt): Use t_reg_operand and fold little and big endian variants.
(*movt_qi): Delete.
2012-07-02 Steven Bosscher <steven@gcc.gnu.org>
* stmt.c (emit_case_bit_tests): Remove.

View File

@ -898,3 +898,42 @@
(match_test "mode != HImode")
(match_test "TARGET_SH4A_ARCH"))))
;; A predicate describing the T bit register in any form.
(define_predicate "t_reg_operand"
(match_code "reg,subreg,sign_extend,zero_extend")
{
switch (GET_CODE (op))
{
case REG:
return REGNO (op) == T_REG;
case SUBREG:
return REGNO (SUBREG_REG (op)) == T_REG;
case ZERO_EXTEND:
case SIGN_EXTEND:
return GET_CODE (XEXP (op, 0)) == SUBREG
&& REGNO (SUBREG_REG (XEXP (op, 0))) == T_REG;
default:
return 0;
}
})
;; A predicate describing a negated T bit register.
(define_predicate "negt_reg_operand"
(match_code "subreg,xor")
{
switch (GET_CODE (op))
{
case XOR:
return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)))
&& satisfies_constraint_M (XEXP (op, 1));
case SUBREG:
return negt_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)));
default:
return 0;
}
})

View File

@ -109,6 +109,7 @@ extern bool sh_vector_mode_supported_p (enum machine_mode);
#endif /* RTX_CODE */
extern const char *output_jump_label_table (void);
extern rtx get_t_reg_rtx (void);
extern rtx get_fpscr_rtx (void);
extern int sh_media_register_for_return (void);
extern void sh_expand_prologue (void);

View File

@ -1874,7 +1874,7 @@ prepare_cbranch_operands (rtx *operands, enum machine_mode mode,
void
expand_cbranchsi4 (rtx *operands, enum rtx_code comparison, int probability)
{
rtx (*branch_expander) (rtx) = gen_branch_true;
rtx (*branch_expander) (rtx, rtx) = gen_branch_true;
rtx jump;
comparison = prepare_cbranch_operands (operands, SImode, comparison);
@ -1888,7 +1888,7 @@ expand_cbranchsi4 (rtx *operands, enum rtx_code comparison, int probability)
emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, T_REG),
gen_rtx_fmt_ee (comparison, SImode,
operands[1], operands[2])));
jump = emit_jump_insn (branch_expander (operands[3]));
jump = emit_jump_insn (branch_expander (operands[3], get_t_reg_rtx ()));
if (probability >= 0)
add_reg_note (jump, REG_BR_PROB, GEN_INT (probability));
@ -1941,7 +1941,7 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
if (TARGET_CMPEQDI_T)
{
emit_insn (gen_cmpeqdi_t (operands[1], operands[2]));
emit_jump_insn (gen_branch_true (operands[3]));
emit_jump_insn (gen_branch_true (operands[3], get_t_reg_rtx ()));
return true;
}
msw_skip = NE;
@ -1969,7 +1969,7 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
if (TARGET_CMPEQDI_T)
{
emit_insn (gen_cmpeqdi_t (operands[1], operands[2]));
emit_jump_insn (gen_branch_false (operands[3]));
emit_jump_insn (gen_branch_false (operands[3], get_t_reg_rtx ()));
return true;
}
msw_taken = NE;
@ -2304,9 +2304,9 @@ sh_emit_compare_and_branch (rtx *operands, enum machine_mode mode)
sh_emit_set_t_insn (gen_ieee_ccmpeqsf_t (op0, op1), mode);
if (branch_code == code)
emit_jump_insn (gen_branch_true (operands[3]));
emit_jump_insn (gen_branch_true (operands[3], get_t_reg_rtx ()));
else
emit_jump_insn (gen_branch_false (operands[3]));
emit_jump_insn (gen_branch_false (operands[3], get_t_reg_rtx ()));
}
void
@ -2340,7 +2340,7 @@ sh_emit_compare_and_set (rtx *operands, enum machine_mode mode)
{
lab = gen_label_rtx ();
sh_emit_scc_to_t (EQ, op0, op1);
emit_jump_insn (gen_branch_true (lab));
emit_jump_insn (gen_branch_true (lab, get_t_reg_rtx ()));
code = GT;
}
else
@ -3360,7 +3360,7 @@ gen_shifty_op (int code, rtx *operands)
if (code == LSHIFTRT)
{
emit_insn (gen_rotlsi3_1 (operands[0], operands[0]));
emit_insn (gen_movt (operands[0]));
emit_insn (gen_movt (operands[0], get_t_reg_rtx ()));
return;
}
else if (code == ASHIFT)
@ -9504,6 +9504,15 @@ reg_unused_after (rtx reg, rtx insn)
#include "ggc.h"
static GTY(()) rtx t_reg_rtx;
rtx
get_t_reg_rtx (void)
{
if (! t_reg_rtx)
t_reg_rtx = gen_rtx_REG (SImode, T_REG);
return t_reg_rtx;
}
static GTY(()) rtx fpscr_rtx;
rtx
get_fpscr_rtx (void)
@ -12049,7 +12058,7 @@ sh_expand_t_scc (rtx operands[])
result = gen_reg_rtx (SImode);
val = INTVAL (op1);
if ((code == EQ && val == 1) || (code == NE && val == 0))
emit_insn (gen_movt (result));
emit_insn (gen_movt (result, get_t_reg_rtx ()));
else if ((code == EQ && val == 0) || (code == NE && val == 1))
emit_insn (gen_movnegt (result));
else if (code == EQ || code == NE)

View File

@ -4450,8 +4450,8 @@ label:
emit_insn (gen_movsi (operands[0], operands[1]));
emit_jump_insn (INTVAL (operands[3])
? gen_branch_true (skip_neg_label)
: gen_branch_false (skip_neg_label));
? gen_branch_true (skip_neg_label, get_t_reg_rtx ())
: gen_branch_false (skip_neg_label, get_t_reg_rtx ()));
emit_label_after (skip_neg_label,
emit_insn (gen_negsi2 (operands[0], operands[1])));
@ -4519,8 +4519,8 @@ label:
emit_insn (gen_movsi (high_dst, high_src));
emit_jump_insn (INTVAL (operands[3])
? gen_branch_true (skip_neg_label)
: gen_branch_false (skip_neg_label));
? gen_branch_true (skip_neg_label, get_t_reg_rtx ())
: gen_branch_false (skip_neg_label, get_t_reg_rtx ()));
if (!INTVAL (operands[3]))
emit_insn (gen_clrt ());
@ -7195,7 +7195,8 @@ label:
;; ------------------------------------------------------------------------
(define_insn "branch_true"
[(set (pc) (if_then_else (ne (reg:SI T_REG) (const_int 0))
[(set (pc) (if_then_else (ne (match_operand 1 "t_reg_operand" "")
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"TARGET_SH1"
@ -7204,31 +7205,9 @@ label:
}
[(set_attr "type" "cbranch")])
;; The *branch_true patterns help combine when trying to invert conditions.
(define_insn "*branch_true"
[(set (pc) (if_then_else (ne (zero_extend:SI (subreg:QI (reg:SI T_REG) 0))
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"TARGET_SH1 && TARGET_LITTLE_ENDIAN"
{
return output_branch (1, insn, operands);
}
[(set_attr "type" "cbranch")])
(define_insn "*branch_true"
[(set (pc) (if_then_else (ne (zero_extend:SI (subreg:QI (reg:SI T_REG) 3))
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"TARGET_SH1 && ! TARGET_LITTLE_ENDIAN"
{
return output_branch (1, insn, operands);
}
[(set_attr "type" "cbranch")])
(define_insn "branch_false"
[(set (pc) (if_then_else (eq (reg:SI T_REG) (const_int 0))
[(set (pc) (if_then_else (eq (match_operand 1 "t_reg_operand" "")
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"TARGET_SH1"
@ -7237,29 +7216,6 @@ label:
}
[(set_attr "type" "cbranch")])
;; The *branch_false patterns help combine when trying to invert conditions.
(define_insn "*branch_false"
[(set (pc) (if_then_else (eq (zero_extend:SI (subreg:QI (reg:SI T_REG) 0))
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"TARGET_SH1 && TARGET_LITTLE_ENDIAN"
{
return output_branch (0, insn, operands);
}
[(set_attr "type" "cbranch")])
(define_insn "*branch_false"
[(set (pc) (if_then_else (eq (zero_extend:SI (subreg:QI (reg:SI T_REG) 3))
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"TARGET_SH1 && ! TARGET_LITTLE_ENDIAN"
{
return output_branch (0, insn, operands);
}
[(set_attr "type" "cbranch")])
;; Patterns to prevent reorg from re-combining a condbranch with a branch
;; which destination is too far away.
;; The const_int_operand is distinct for each branch target; it avoids
@ -9672,7 +9628,7 @@ label:
(define_insn "movt"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(eq:SI (reg:SI T_REG) (const_int 1)))]
(match_operand:SI 1 "t_reg_operand"))]
"TARGET_SH1"
"movt %0"
[(set_attr "type" "arith")])
@ -9854,62 +9810,25 @@ label:
"negc %1,%0"
[(set_attr "type" "arith")])
;; The *negnegt patterns help the combine pass to figure out how to fold
;; The *negnegt pattern helps the combine pass to figure out how to fold
;; an explicit double T bit negation.
(define_insn_and_split "*negnegt"
[(set (reg:SI T_REG)
(eq:SI (subreg:QI (xor:SI (reg:SI T_REG) (const_int 1)) 3)
(const_int 0)))]
"! TARGET_LITTLE_ENDIAN"
(eq:SI (match_operand 0 "negt_reg_operand" "") (const_int 0)))]
"TARGET_SH1"
"#"
""
[(const_int 0)])
(define_insn_and_split "*negnegt"
[(set (reg:SI T_REG)
(eq:SI (subreg:QI (xor:SI (reg:SI T_REG) (const_int 1)) 0)
(const_int 0)))]
"TARGET_LITTLE_ENDIAN"
"#"
""
[(const_int 0)])
;; The *movtt patterns eliminate redundant T bit to T bit moves / tests.
;; The *movtt pattern eliminates redundant T bit to T bit moves / tests.
(define_insn_and_split "*movtt"
[(set (reg:SI T_REG)
(eq:SI (zero_extend:SI (subreg:QI (reg:SI T_REG) 3))
(const_int 1)))]
"! TARGET_LITTLE_ENDIAN"
(eq:SI (match_operand 0 "t_reg_operand" "") (const_int 1)))]
"TARGET_SH1"
"#"
""
[(const_int 0)])
(define_insn_and_split "*movtt"
[(set (reg:SI T_REG)
(eq:SI (zero_extend:SI (subreg:QI (reg:SI T_REG) 0))
(const_int 1)))]
"TARGET_LITTLE_ENDIAN"
"#"
""
[(const_int 0)])
;; The *movt_qi patterns help the combine pass convert a movrt_negc pattern
;; into a movt Rn, xor #1 Rn pattern. This can happen when e.g. a function
;; returns the inverted T bit value.
(define_insn "*movt_qi"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(zero_extend:SI (subreg:QI (reg:SI T_REG) 3)))]
"! TARGET_LITTLE_ENDIAN"
"movt %0"
[(set_attr "type" "arith")])
(define_insn "*movt_qi"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(zero_extend:SI (subreg:QI (reg:SI T_REG) 0)))]
"TARGET_LITTLE_ENDIAN"
"movt %0"
[(set_attr "type" "arith")])
(define_expand "cstoresf4"
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operator:SI 1 "sh_float_comparison_operator"
@ -13960,7 +13879,7 @@ label:
else
{
emit_insn (gen_stack_protect_test_si (operands[0], operands[1]));
emit_jump_insn (gen_branch_true (operands[2]));
emit_jump_insn (gen_branch_true (operands[2], get_t_reg_rtx ()));
}
DONE;

View File

@ -1,3 +1,8 @@
2012-07-02 Oleg Endo <olegendo@gcc.gnu.org>
PR target/51244
* gcc.target/sh/pr51244-1.c: Check that movt insn is not generated.
2012-07-02 Jason Merrill <jason@redhat.com>
PR c++/53821

View File

@ -4,7 +4,7 @@
/* { dg-do compile { target "sh*-*-*" } } */
/* { dg-options "-O1 -mbranch-cost=2" } */
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */
/* { dg-final { scan-assembler-not "tst|negc|extu" } } */
/* { dg-final { scan-assembler-not "movt|tst|negc|extu" } } */
int
testfunc_00 (int a, int b, int c, int d)