Commit 669d4d70 by Oleg Endo

re PR target/52933 (SH Target: Use div0s for integer sign comparisons)

	PR target/52933
	* config/sh/sh.md (cmp_div0s_0, cmp_div0s_1, *cmp_div0s_0,
	*cmp_div0s_1, *cbranch_div0s, *movsicc_div0s): New insns.
	* config/sh/sh.c (sh_rtx_costs): Handle div0s patterns.

	PR target/52933
	* gcc.target/sh/pr52933-1.c: New.
	* gcc.target/sh/pr52933-2.c: New.

From-SVN: r190396
parent 24c18ad8
2012-08-14 Oleg Endo <olegendo@gcc.gnu.org> 2012-08-14 Oleg Endo <olegendo@gcc.gnu.org>
PR target/52933
* config/sh/sh.md (cmp_div0s_0, cmp_div0s_1, *cmp_div0s_0,
*cmp_div0s_1, *cbranch_div0s, *movsicc_div0s): New insns.
* config/sh/sh.c (sh_rtx_costs): Handle div0s patterns.
2012-08-14 Oleg Endo <olegendo@gcc.gnu.org>
PR target/50751 PR target/50751
* config/sh/constraints.md (Sra): New constraint. * config/sh/constraints.md (Sra): New constraint.
* config/sh/predicates.md (simple_mem_operand, * config/sh/predicates.md (simple_mem_operand,
......
...@@ -3186,9 +3186,33 @@ sh_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED, ...@@ -3186,9 +3186,33 @@ sh_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
*total = COSTS_N_INSNS (multcosts (x)); *total = COSTS_N_INSNS (multcosts (x));
return true; return true;
case LT:
case GE:
/* div0s sign comparison. */
if (GET_CODE (XEXP (x, 0)) == XOR
&& REG_P ((XEXP (XEXP (x, 0), 0)))
&& REG_P ((XEXP (XEXP (x, 0), 1)))
&& satisfies_constraint_Z (XEXP (x, 1)))
{
*total = COSTS_N_INSNS (1);
return true;
}
else
return false;
case LSHIFTRT:
/* div0s sign comparison. */
if (GET_CODE (XEXP (x, 0)) == XOR
&& REG_P ((XEXP (XEXP (x, 0), 0)))
&& REG_P ((XEXP (XEXP (x, 0), 1)))
&& CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) == 31)
{
*total = COSTS_N_INSNS (1);
return true;
}
/* Fall through to shiftcosts. */
case ASHIFT: case ASHIFT:
case ASHIFTRT: case ASHIFTRT:
case LSHIFTRT:
{ {
int cost = shiftcosts (x); int cost = shiftcosts (x);
if (cost < 0) if (cost < 0)
......
...@@ -801,6 +801,70 @@ ...@@ -801,6 +801,70 @@
"cmp/pl %0" "cmp/pl %0"
[(set_attr "type" "mt_group")]) [(set_attr "type" "mt_group")])
;; Some integer sign comparison patterns can be realized with the div0s insn.
;; div0s Rm,Rn T = (Rm >> 31) ^ (Rn >> 31)
(define_insn "cmp_div0s_0"
[(set (reg:SI T_REG)
(lshiftrt:SI (xor:SI (match_operand:SI 0 "arith_reg_operand" "%r")
(match_operand:SI 1 "arith_reg_operand" "r"))
(const_int 31)))]
"TARGET_SH1"
"div0s %0,%1"
[(set_attr "type" "arith")])
(define_insn "cmp_div0s_1"
[(set (reg:SI T_REG)
(lt:SI (xor:SI (match_operand:SI 0 "arith_reg_operand" "%r")
(match_operand:SI 1 "arith_reg_operand" "r"))
(const_int 0)))]
"TARGET_SH1"
"div0s %0,%1"
[(set_attr "type" "arith")])
(define_insn_and_split "*cmp_div0s_0"
[(set (match_operand:SI 0 "arith_reg_dest" "")
(lshiftrt:SI (xor:SI (match_operand:SI 1 "arith_reg_operand" "")
(match_operand:SI 2 "arith_reg_operand" ""))
(const_int 31)))
(clobber (reg:SI T_REG))]
"TARGET_SH1"
"#"
"&& 1"
[(set (reg:SI T_REG)
(lshiftrt:SI (xor:SI (match_dup 1) (match_dup 2)) (const_int 31)))
(set (match_dup 0) (reg:SI T_REG))])
(define_insn_and_split "*cmp_div0s_1"
[(set (match_operand:SI 0 "arith_reg_dest" "")
(ge:SI (xor:SI (match_operand:SI 1 "arith_reg_operand" "")
(match_operand:SI 2 "arith_reg_operand" ""))
(const_int 0)))
(clobber (reg:SI T_REG))]
"TARGET_SH1"
"#"
"&& can_create_pseudo_p ()"
[(const_int 0)]
;; We have to go through the movnegt expander here which will handle the
;; SH2A vs non-SH2A cases.
{
emit_insn (gen_cmp_div0s_1 (operands[1], operands[2]));
emit_insn (gen_movnegt (operands[0], get_t_reg_rtx ()));
DONE;
})
(define_insn_and_split "*cmp_div0s_1"
[(set (reg:SI T_REG)
(ge:SI (xor:SI (match_operand:SI 0 "arith_reg_operand" "")
(match_operand:SI 1 "arith_reg_operand" ""))
(const_int 0)))]
"TARGET_SH1"
"#"
"&& can_create_pseudo_p ()"
[(set (reg:SI T_REG) (lt:SI (xor:SI (match_dup 0) (match_dup 1))
(const_int 0)))
(set (reg:SI T_REG) (xor:SI (reg:SI T_REG) (const_int 1)))])
;; ------------------------------------------------------------------------- ;; -------------------------------------------------------------------------
;; SImode compare and branch ;; SImode compare and branch
;; ------------------------------------------------------------------------- ;; -------------------------------------------------------------------------
...@@ -918,6 +982,63 @@ ...@@ -918,6 +982,63 @@
(label_ref (match_dup 2)) (label_ref (match_dup 2))
(pc)))]) (pc)))])
;; Compare and branch combine patterns for div0s comparisons.
(define_insn_and_split "*cbranch_div0s"
[(set (pc)
(if_then_else (lt (xor:SI (match_operand:SI 0 "arith_reg_operand" "")
(match_operand:SI 1 "arith_reg_operand" ""))
(const_int 0))
(label_ref (match_operand 2))
(pc)))
(clobber (reg:SI T_REG))]
"TARGET_SH1"
"#"
"&& 1"
[(set (reg:SI T_REG)
(lt:SI (xor:SI (match_dup 0) (match_dup 1)) (const_int 0)))
(set (pc)
(if_then_else (ne (reg:SI T_REG) (const_int 0))
(label_ref (match_dup 2))
(pc)))])
(define_insn_and_split "*cbranch_div0s"
[(set (pc)
(if_then_else (ge (xor:SI (match_operand:SI 0 "arith_reg_operand" "")
(match_operand:SI 1 "arith_reg_operand" ""))
(const_int 0))
(label_ref (match_operand 2))
(pc)))
(clobber (reg:SI T_REG))]
"TARGET_SH1"
"#"
"&& 1"
[(set (reg:SI T_REG)
(lt:SI (xor:SI (match_dup 0) (match_dup 1)) (const_int 0)))
(set (pc)
(if_then_else (eq (reg:SI T_REG) (const_int 0))
(label_ref (match_dup 2))
(pc)))])
;; Conditional move combine pattern for div0s comparisons.
;; This is used when TARGET_PRETEND_CMOVE is in effect.
(define_insn_and_split "*movsicc_div0s"
[(set (match_operand:SI 0 "arith_reg_dest" "")
(if_then_else:SI (ge (xor:SI (match_operand:SI 1 "arith_reg_operand" "")
(match_operand:SI 2 "arith_reg_operand" ""))
(const_int 0))
(match_operand:SI 3 "arith_reg_operand" "")
(match_operand:SI 4 "general_movsrc_operand" "")))
(clobber (reg:SI T_REG))]
"TARGET_PRETEND_CMOVE"
"#"
"&& 1"
[(set (reg:SI T_REG) (lt:SI (xor:SI (match_dup 1) (match_dup 2))
(const_int 0)))
(set (match_dup 0)
(if_then_else (ne (reg:SI T_REG) (const_int 0))
(match_dup 4)
(match_dup 3)))])
;; ------------------------------------------------------------------------- ;; -------------------------------------------------------------------------
;; SImode unsigned integer comparisons ;; SImode unsigned integer comparisons
;; ------------------------------------------------------------------------- ;; -------------------------------------------------------------------------
......
2012-08-14 Oleg Endo <olegendo@gcc.gnu.org> 2012-08-14 Oleg Endo <olegendo@gcc.gnu.org>
PR target/52933
* gcc.target/sh/pr52933-1.c: New.
* gcc.target/sh/pr52933-2.c: New.
2012-08-14 Oleg Endo <olegendo@gcc.gnu.org>
PR target/50751 PR target/50751
* gcc.target/sh/pr50751-8.c: New. * gcc.target/sh/pr50751-8.c: New.
......
/* Check that the div0s instruction is used for integer sign comparisons.
Each test case is expected to emit at least one div0s insn.
Problems when combining the div0s comparison result with surrounding
logic usually show up as redundant tst insns. */
/* { dg-do compile { target "sh*-*-*" } } */
/* { dg-options "-O2" } */
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
/* { dg-final { scan-assembler-times "div0s" 25 } } */
/* { dg-final { scan-assembler-not "tst" } } */
typedef unsigned char bool;
int other_func_a (int, int);
int other_func_b (int, int);
bool
test_00 (int a, int b)
{
return (a ^ b) >= 0;
}
bool
test_01 (int a, int b)
{
return (a ^ b) < 0;
}
int
test_02 (int a, int b, int c, int d)
{
if ((a ^ b) < 0)
return other_func_a (a, c);
else
return other_func_b (d, b);
}
int
test_03 (int a, int b, int c, int d)
{
if ((a ^ b) >= 0)
return other_func_a (a, c);
else
return other_func_b (d, b);
}
int
test_04 (int a, int b)
{
return (a ^ b) >= 0 ? -20 : -40;
}
bool
test_05 (int a, int b)
{
return (a ^ b) < 0;
}
int
test_06 (int a, int b)
{
return (a ^ b) < 0 ? -20 : -40;
}
bool
test_07 (int a, int b)
{
return (a < 0) == (b < 0);
}
int
test_08 (int a, int b)
{
return (a < 0) == (b < 0) ? -20 : -40;
}
bool
test_09 (int a, int b)
{
return (a < 0) != (b < 0);
}
int
test_10 (int a, int b)
{
return (a < 0) != (b < 0) ? -20 : -40;
}
bool
test_11 (int a, int b)
{
return (a >= 0) ^ (b < 0);
}
int
test_12 (int a, int b)
{
return (a >= 0) ^ (b < 0) ? -20 : -40;
}
bool
test_13 (int a, int b)
{
return !((a >= 0) ^ (b < 0));
}
int
test_14 (int a, int b)
{
return !((a >= 0) ^ (b < 0)) ? -20 : -40;
}
bool
test_15 (int a, int b)
{
return (a & 0x80000000) == (b & 0x80000000);
}
int
test_16 (int a, int b)
{
return (a & 0x80000000) == (b & 0x80000000) ? -20 : -40;
}
bool
test_17 (int a, int b)
{
return (a & 0x80000000) != (b & 0x80000000);
}
int
test_18 (int a, int b)
{
return (a & 0x80000000) != (b & 0x80000000) ? -20 : -40;
}
int
test_19 (unsigned int a, unsigned int b)
{
return (a ^ b) >> 31;
}
int
test_20 (unsigned int a, unsigned int b)
{
return (a >> 31) ^ (b >> 31);
}
int
test_21 (int a, int b)
{
return ((a & 0x80000000) ^ (b & 0x80000000)) >> 31 ? -30 : -10;
}
int
test_22 (int a, int b, int c, int d)
{
if ((a < 0) == (b < 0))
return other_func_a (a, b);
else
return other_func_b (c, d);
}
bool
test_23 (int a, int b, int c, int d)
{
/* Should emit 2x div0s. */
return ((a < 0) == (b < 0)) | ((c < 0) == (d < 0));
}
/* Check that the div0s instruction is used for integer sign comparisons
when -mpretend-cmove is enabled.
Each test case is expected to emit at least one div0s insn.
Problems when combining the div0s comparison result with surrounding
logic usually show up as redundant tst insns. */
/* { dg-do compile { target "sh*-*-*" } } */
/* { dg-options "-O2 -mpretend-cmove" } */
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
/* { dg-final { scan-assembler-times "div0s" 25 } } */
/* { dg-final { scan-assembler-not "tst" } } */
#include "pr52933-1.c"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment