+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
{
/* 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;
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);
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;
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;
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)
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
;; 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
[(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