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
This commit is contained in:
Oleg Endo 2012-08-14 17:59:03 +00:00
parent 24c18ad8f1
commit 669d4d702b
6 changed files with 339 additions and 1 deletions

View File

@ -1,3 +1,10 @@
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

View File

@ -3186,9 +3186,33 @@ sh_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
*total = COSTS_N_INSNS (multcosts (x));
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 ASHIFTRT:
case LSHIFTRT:
{
int cost = shiftcosts (x);
if (cost < 0)

View File

@ -801,6 +801,70 @@
"cmp/pl %0"
[(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
;; -------------------------------------------------------------------------
@ -918,6 +982,63 @@
(label_ref (match_dup 2))
(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
;; -------------------------------------------------------------------------

View File

@ -1,3 +1,9 @@
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

View File

@ -0,0 +1,168 @@
/* 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));
}

View File

@ -0,0 +1,12 @@
/* 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"