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:
parent
9ce85efc60
commit
355e99758b
4 changed files with 124 additions and 86 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue