re PR target/63986 ([SH] gcc.target/sh/pr51244-15.c failures)

gcc/
	PR target/63986
	PR target/51244
	* config/sh/sh.c (sh_is_logical_t_store_expr,
	sh_try_omit_signzero_extend): Use rtx_insn* for insn argument.
	(sh_split_movrt_negc_to_movt_xor): New function.
	(sh_find_set_of_reg): Move to ...
	* config/sh/sh-protos.h (sh_find_set_of_reg): ... here and convert
	to template function.
	(set_of_reg): Use rtx_insn* for insn member.
	(sh_is_logical_t_store_expr, sh_try_omit_signzero_extend): Use
	rtx_insn* for insn argument.
	* config/sh/sh.md (movrt_negc, *movrt_negc): Split into movt-xor
	sequence using new sh_split_movrt_negc_to_movt_xor function.
	(movrt_xor): Allow also for SH2A.
	(*movt_movrt): Delete insns and splits.

From-SVN: r217968
This commit is contained in:
Oleg Endo 2014-11-22 15:06:34 +00:00
parent 9ce85efc60
commit 355e99758b
4 changed files with 124 additions and 86 deletions

View file

@ -1,3 +1,21 @@
2014-11-22 Oleg Endo <olegendo@gcc.gnu.org>
PR target/63986
PR target/51244
* config/sh/sh.c (sh_is_logical_t_store_expr,
sh_try_omit_signzero_extend): Use rtx_insn* for insn argument.
(sh_split_movrt_negc_to_movt_xor): New function.
(sh_find_set_of_reg): Move to ...
* config/sh/sh-protos.h (sh_find_set_of_reg): ... here and convert
to template function.
(set_of_reg): Use rtx_insn* for insn member.
(sh_is_logical_t_store_expr, sh_try_omit_signzero_extend): Use
rtx_insn* for insn argument.
* config/sh/sh.md (movrt_negc, *movrt_negc): Split into movt-xor
sequence using new sh_split_movrt_negc_to_movt_xor function.
(movrt_xor): Allow also for SH2A.
(*movt_movrt): Delete insns and splits.
2014-11-22 Marc Glisse <marc.glisse@inria.fr>
PR tree-optimization/60770

View file

@ -165,7 +165,7 @@ struct set_of_reg
{
/* The insn where sh_find_set_of_reg stopped looking.
Can be NULL_RTX if the end of the insn list was reached. */
rtx insn;
rtx_insn* insn;
/* The set rtx of the specified reg if found, NULL_RTX otherwise. */
const_rtx set_rtx;
@ -175,9 +175,47 @@ struct set_of_reg
rtx set_src;
};
extern set_of_reg sh_find_set_of_reg (rtx reg, rtx insn, rtx_insn *(*stepfunc)(rtx));
extern bool sh_is_logical_t_store_expr (rtx op, rtx insn);
extern rtx sh_try_omit_signzero_extend (rtx extended_op, rtx insn);
/* Given a reg rtx and a start insn, try to find the insn that sets the
specified reg by using the specified insn stepping function, such as
'prev_nonnote_insn_bb'. When the insn is found, try to extract the rtx
of the reg set. */
template <typename F> inline set_of_reg
sh_find_set_of_reg (rtx reg, rtx_insn* insn, F stepfunc)
{
set_of_reg result;
result.insn = insn;
result.set_rtx = NULL_RTX;
result.set_src = NULL_RTX;
if (!REG_P (reg) || insn == NULL_RTX)
return result;
for (result.insn = stepfunc (insn); result.insn != NULL_RTX;
result.insn = stepfunc (result.insn))
{
if (BARRIER_P (result.insn))
return result;
if (!NONJUMP_INSN_P (result.insn))
continue;
if (reg_set_p (reg, result.insn))
{
result.set_rtx = set_of (reg, result.insn);
if (result.set_rtx == NULL_RTX || GET_CODE (result.set_rtx) != SET)
return result;
result.set_src = XEXP (result.set_rtx, 1);
return result;
}
}
return result;
}
extern bool sh_is_logical_t_store_expr (rtx op, rtx_insn* insn);
extern rtx sh_try_omit_signzero_extend (rtx extended_op, rtx_insn* insn);
extern bool sh_split_movrt_negc_to_movt_xor (rtx_insn* curr_insn,
rtx operands[]);
#endif /* RTX_CODE */
extern void sh_cpu_cpp_builtins (cpp_reader* pfile);

View file

@ -13503,47 +13503,10 @@ sh_find_equiv_gbr_addr (rtx_insn* insn, rtx mem)
Manual insn combine support code.
*/
/* Given a reg rtx and a start insn, try to find the insn that sets the
specified reg by using the specified insn stepping function, such as
'prev_nonnote_insn_bb'. When the insn is found, try to extract the rtx
of the reg set. */
set_of_reg
sh_find_set_of_reg (rtx reg, rtx insn, rtx_insn *(*stepfunc)(rtx))
{
set_of_reg result;
result.insn = insn;
result.set_rtx = NULL_RTX;
result.set_src = NULL_RTX;
if (!REG_P (reg) || insn == NULL_RTX)
return result;
for (result.insn = stepfunc (insn); result.insn != NULL_RTX;
result.insn = stepfunc (result.insn))
{
if (BARRIER_P (result.insn))
return result;
if (!NONJUMP_INSN_P (result.insn))
continue;
if (reg_set_p (reg, result.insn))
{
result.set_rtx = set_of (reg, result.insn);
if (result.set_rtx == NULL_RTX || GET_CODE (result.set_rtx) != SET)
return result;
result.set_src = XEXP (result.set_rtx, 1);
return result;
}
}
return result;
}
/* Given an op rtx and an insn, try to find out whether the result of the
specified op consists only of logical operations on T bit stores. */
bool
sh_is_logical_t_store_expr (rtx op, rtx insn)
sh_is_logical_t_store_expr (rtx op, rtx_insn* insn)
{
if (!logical_operator (op, SImode))
return false;
@ -13579,7 +13542,7 @@ sh_is_logical_t_store_expr (rtx op, rtx insn)
by a simple reg-reg copy. If so, the replacement reg rtx is returned,
NULL_RTX otherwise. */
rtx
sh_try_omit_signzero_extend (rtx extended_op, rtx insn)
sh_try_omit_signzero_extend (rtx extended_op, rtx_insn* insn)
{
if (REG_P (extended_op))
extended_op = extended_op;
@ -13609,6 +13572,42 @@ sh_try_omit_signzero_extend (rtx extended_op, rtx insn)
return NULL_RTX;
}
/* Given the current insn, which is assumed to be a movrt_negc insn, try to
figure out whether it should be converted into a movt-xor sequence in
the movrt_negc splitter.
Returns true if insns have been modified and the splitter has succeeded. */
bool
sh_split_movrt_negc_to_movt_xor (rtx_insn* curr_insn, rtx operands[])
{
/* In cases such as
tst r4,r4
mov #-1,r1
negc r1,r1
tst r4,r4
we can replace the T bit clobbering negc with a movt-xor sequence and
eliminate the redundant comparison.
Because the xor insn depends on register allocation results, allow this
only before reload. */
if (!can_create_pseudo_p ())
return false;
set_of_reg t_before_negc = sh_find_set_of_reg (get_t_reg_rtx (), curr_insn,
prev_nonnote_insn_bb);
set_of_reg t_after_negc = sh_find_set_of_reg (get_t_reg_rtx (), curr_insn,
next_nonnote_insn_bb);
if (t_before_negc.set_rtx != NULL_RTX && t_after_negc.set_rtx != NULL_RTX
&& rtx_equal_p (t_before_negc.set_rtx, t_after_negc.set_rtx)
&& !reg_used_between_p (get_t_reg_rtx (), curr_insn, t_after_negc.insn))
{
emit_insn (gen_movrt_xor (operands[0], get_t_reg_rtx ()));
set_insn_deleted (t_after_negc.insn);
return true;
}
else
return false;
}
static void
sh_emit_mode_set (int entity ATTRIBUTE_UNUSED, int mode,
int prev_mode, HARD_REG_SET regs_live ATTRIBUTE_UNUSED)

View file

@ -11445,13 +11445,21 @@ label:
DONE;
})
(define_insn "movrt_negc"
(define_insn_and_split "movrt_negc"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(xor:SI (match_operand:SI 1 "t_reg_operand" "") (const_int 1)))
(xor:SI (match_operand:SI 1 "t_reg_operand") (const_int 1)))
(set (reg:SI T_REG) (const_int 1))
(use (match_operand:SI 2 "arith_reg_operand" "r"))]
"TARGET_SH1"
"negc %2,%0"
"&& 1"
[(const_int 0)]
{
if (sh_split_movrt_negc_to_movt_xor (curr_insn, operands))
DONE;
else
FAIL;
}
[(set_attr "type" "arith")])
;; The -1 constant will not be CSE-ed for the *movrt_negc pattern, but the
@ -11460,17 +11468,25 @@ label:
;; generating a pseudo reg before reload.
(define_insn_and_split "*movrt_negc"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(xor:SI (match_operand:SI 1 "t_reg_operand" "") (const_int 1)))
(xor:SI (match_operand:SI 1 "t_reg_operand") (const_int 1)))
(clobber (match_scratch:SI 2 "=r"))
(clobber (reg:SI T_REG))]
"TARGET_SH1 && ! TARGET_SH2A"
"#"
"&& reload_completed"
[(set (match_dup 2) (const_int -1))
(parallel
[(set (match_dup 0) (xor:SI (match_dup 1) (const_int 1)))
(set (reg:SI T_REG) (const_int 1))
(use (match_dup 2))])])
"&& 1"
[(const_int 0)]
{
if (sh_split_movrt_negc_to_movt_xor (curr_insn, operands))
DONE;
else if (reload_completed)
{
emit_move_insn (operands[2], gen_int_mode (-1, SImode));
emit_insn (gen_movrt_negc (operands[0], operands[1], operands[2]));
DONE;
}
else
FAIL;
})
;; Store the negated T bit in a reg using r0 and xor. This one doesn't
;; clobber the T bit, which is useful when storing the T bit and the
@ -11481,45 +11497,12 @@ label:
[(set (match_operand:SI 0 "arith_reg_dest" "=z")
(xor:SI (match_operand:SI 1 "t_reg_operand") (const_int 1)))
(use (reg:SI T_REG))]
"TARGET_SH1 && !TARGET_SH2A"
"TARGET_SH1"
"#"
"&& reload_completed"
[(set (match_dup 0) (reg:SI T_REG))
(set (match_dup 0) (xor:SI (match_dup 0) (const_int 1)))])
;; Store the T bit and the negated T bit in two regs in parallel. There is
;; no real insn to do that, but specifying this pattern will give combine
;; some opportunities.
(define_insn_and_split "*movt_movrt"
[(parallel [(set (match_operand:SI 0 "arith_reg_dest")
(match_operand:SI 1 "negt_reg_operand"))
(set (match_operand:SI 2 "arith_reg_dest")
(match_operand:SI 3 "t_reg_operand"))])]
"TARGET_SH1"
"#"
"&& 1"
[(const_int 0)]
{
rtx i = TARGET_SH2A
? gen_movrt (operands[0], get_t_reg_rtx ())
: gen_movrt_xor (operands[0], get_t_reg_rtx ());
emit_insn (i);
emit_insn (gen_movt (operands[2], get_t_reg_rtx ()));
DONE;
})
(define_insn_and_split "*movt_movrt"
[(parallel [(set (match_operand:SI 0 "arith_reg_dest")
(match_operand:SI 1 "t_reg_operand"))
(set (match_operand:SI 2 "arith_reg_dest")
(match_operand:SI 3 "negt_reg_operand"))])]
"TARGET_SH1"
"#"
"&& 1"
[(parallel [(set (match_dup 2) (match_dup 3))
(set (match_dup 0) (match_dup 1))])])
;; Use negc to store the T bit in a MSB of a reg in the following way:
;; T = 1: 0x80000000 -> reg
;; T = 0: 0x7FFFFFFF -> reg