diff options
author | Oleg Endo <olegendo@gcc.gnu.org> | 2012-08-14 17:59:03 +0000 |
---|---|---|
committer | Oleg Endo <olegendo@gcc.gnu.org> | 2012-08-14 17:59:03 +0000 |
commit | 669d4d702b35346b357bf77c194029eb96ba13b6 (patch) | |
tree | 629b7e509bd0dbb34c8e9c2ec44996dc9d68abba | |
parent | 24c18ad8f18bc0f02ce6c7d85e1f38f7d8760925 (diff) | |
download | gcc-669d4d702b35346b357bf77c194029eb96ba13b6.zip gcc-669d4d702b35346b357bf77c194029eb96ba13b6.tar.gz gcc-669d4d702b35346b357bf77c194029eb96ba13b6.tar.bz2 |
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
-rw-r--r-- | gcc/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/config/sh/sh.c | 26 | ||||
-rw-r--r-- | gcc/config/sh/sh.md | 121 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/sh/pr52933-1.c | 168 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/sh/pr52933-2.c | 12 |
6 files changed, 339 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5b7457b..4f3aa1c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,12 @@ 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 * config/sh/constraints.md (Sra): New constraint. * config/sh/predicates.md (simple_mem_operand, diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index bac849b..263ea3a 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -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) diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index 3462dd1..5d6fc84 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -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 ;; ------------------------------------------------------------------------- diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c1325cd..d00816e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,11 @@ 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 * gcc.target/sh/pr50751-8.c: New. diff --git a/gcc/testsuite/gcc.target/sh/pr52933-1.c b/gcc/testsuite/gcc.target/sh/pr52933-1.c new file mode 100644 index 0000000..037f916 --- /dev/null +++ b/gcc/testsuite/gcc.target/sh/pr52933-1.c @@ -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)); +} diff --git a/gcc/testsuite/gcc.target/sh/pr52933-2.c b/gcc/testsuite/gcc.target/sh/pr52933-2.c new file mode 100644 index 0000000..b0e650b --- /dev/null +++ b/gcc/testsuite/gcc.target/sh/pr52933-2.c @@ -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" |