mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-14 00:21:05 +08:00
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:
parent
24c18ad8f1
commit
669d4d702b
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
;; -------------------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
168
gcc/testsuite/gcc.target/sh/pr52933-1.c
Normal file
168
gcc/testsuite/gcc.target/sh/pr52933-1.c
Normal 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));
|
||||
}
|
12
gcc/testsuite/gcc.target/sh/pr52933-2.c
Normal file
12
gcc/testsuite/gcc.target/sh/pr52933-2.c
Normal 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"
|
Loading…
x
Reference in New Issue
Block a user