From: Oleg Endo Date: Tue, 29 Oct 2013 20:45:56 +0000 (+0000) Subject: re PR target/54236 ([SH] Improve addc and subc insn utilization) X-Git-Tag: releases/gcc-4.9.0~3166 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dd331dd0b5925b1b5ef8b740af0bd2e590248603;p=thirdparty%2Fgcc.git re PR target/54236 ([SH] Improve addc and subc insn utilization) PR target/54236 * config/sh/sh.md (*addc): Rename existing variations to ... (*addc_r_r_1, *addc_2r_1, *addc_r_1): ... these. (*addc_r_lsb, *addc_r_r_lsb, *addc_r_lsb_r, *addc_2r_lsb, *addc_r_msb, *addc_r_r_msb, *addc_2r_msb): New insn_and_split patterns. * config/sh/sh.c (addsubcosts): Handle some addc special cases. PR target/54236 * gcc.target/sh/pr54236-2: New. * gcc.target/sh/pr54089-6: Add another rotl special case. From-SVN: r204180 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d7be352cb881..4c1cc9cac4ec 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2013-10-29 Oleg Endo + + PR target/54236 + * config/sh/sh.md (*addc): Rename existing variations to ... + (*addc_r_r_1, *addc_2r_1, *addc_r_1): ... these. + (*addc_r_lsb, *addc_r_r_lsb, *addc_r_lsb_r, *addc_2r_lsb, *addc_r_msb, + *addc_r_r_msb, *addc_2r_msb): New insn_and_split patterns. + * config/sh/sh.c (addsubcosts): Handle some addc special cases. + 2013-10-29 Teresa Johnson PR ipa/58862 diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index ae4b7a525b6f..167b615e37b1 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -3159,6 +3159,35 @@ and_xor_ior_costs (rtx x, int code) static inline int addsubcosts (rtx x) { + if (GET_MODE (x) == SImode) + { + /* The addc or subc patterns will eventually become one or two + instructions. Below are some costs for some of the patterns + which combine would reject because the costs of the individual + insns in the patterns are lower. + + FIXME: It would be much easier if we had something like insn cost + attributes and the cost calculation machinery used those attributes + in the first place. This would eliminate redundant recog-like C + code to calculate costs of complex patterns. */ + rtx op0 = XEXP (x, 0); + rtx op1 = XEXP (x, 1); + + if (GET_CODE (x) == PLUS) + { + if (GET_CODE (op0) == AND + && XEXP (op0, 1) == const1_rtx + && (GET_CODE (op1) == PLUS + || (GET_CODE (op1) == MULT && XEXP (op1, 1) == const2_rtx))) + return 1; + + if (GET_CODE (op0) == MULT && XEXP (op0, 1) == const2_rtx + && GET_CODE (op1) == LSHIFTRT + && CONST_INT_P (XEXP (op1, 1)) && INTVAL (XEXP (op1, 1)) == 31) + return 1; + } + } + /* On SH1-4 we have only max. SImode operations. Double the cost for modes > SImode. */ const int cost_scale = !TARGET_SHMEDIA diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index db4f8d2974a3..0b952991039d 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -1841,7 +1841,7 @@ ;; Split 'reg + reg + 1' into a sett addc sequence, as it can be scheduled ;; better, if the sett insn can be done early. -(define_insn_and_split "*addc" +(define_insn_and_split "*addc_r_r_1" [(set (match_operand:SI 0 "arith_reg_dest" "") (plus:SI (plus:SI (match_operand:SI 1 "arith_reg_operand" "") (match_operand:SI 2 "arith_reg_operand" "")) @@ -1857,7 +1857,7 @@ ;; Left shifts by one are usually done with an add insn to avoid T_REG ;; clobbers. Thus addc can also be used to do something like '(x << 1) + 1'. -(define_insn_and_split "*addc" +(define_insn_and_split "*addc_2r_1" [(set (match_operand:SI 0 "arith_reg_dest") (plus:SI (mult:SI (match_operand:SI 1 "arith_reg_operand") (const_int 2)) @@ -1897,7 +1897,7 @@ ;; can be scheduled much better since the load of the constant can be ;; done earlier, before any comparison insns that store the result in ;; the T bit. -(define_insn_and_split "*addc" +(define_insn_and_split "*addc_r_1" [(set (match_operand:SI 0 "arith_reg_dest" "") (plus:SI (match_operand:SI 1 "t_reg_operand" "") (match_operand:SI 2 "arith_reg_operand" ""))) @@ -1910,6 +1910,126 @@ (match_dup 1))) (clobber (reg:SI T_REG))])]) +;; Use shlr-addc to do 'reg + (reg & 1)'. +(define_insn_and_split "*addc_r_lsb" + [(set (match_operand:SI 0 "arith_reg_dest") + (plus:SI (and:SI (match_operand:SI 1 "arith_reg_operand") + (const_int 1)) + (match_operand:SI 2 "arith_reg_operand"))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& can_create_pseudo_p ()" + [(parallel [(set (match_dup 0) (plus:SI (reg:SI T_REG) (match_dup 2))) + (clobber (reg:SI T_REG))])] +{ + emit_insn (gen_shlr (gen_reg_rtx (SImode), operands[1])); +}) + +;; Use shlr-addc to do 'reg + reg + (reg & 1)'. +(define_insn_and_split "*addc_r_r_lsb" + [(set (match_operand:SI 0 "arith_reg_dest") + (plus:SI (plus:SI (and:SI (match_operand:SI 1 "arith_reg_operand") + (const_int 1)) + (match_operand:SI 2 "arith_reg_operand")) + (match_operand:SI 3 "arith_reg_operand"))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& can_create_pseudo_p ()" + [(parallel [(set (match_dup 0) (plus:SI (plus:SI (match_dup 2) (match_dup 3)) + (reg:SI T_REG))) + (clobber (reg:SI T_REG))])] +{ + emit_insn (gen_shlr (gen_reg_rtx (SImode), operands[1])); +}) + +;; Canonicalize 'reg + (reg & 1) + reg' into 'reg + reg + (reg & 1)'. +(define_insn_and_split "*addc_r_lsb_r" + [(set (match_operand:SI 0 "arith_reg_dest") + (plus:SI (and:SI (match_operand:SI 1 "arith_reg_operand") + (const_int 1)) + (plus:SI (match_operand:SI 2 "arith_reg_operand") + (match_operand:SI 3 "arith_reg_operand")))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& can_create_pseudo_p ()" + [(parallel [(set (match_dup 0) + (plus:SI (plus:SI (and:SI (match_dup 1) (const_int 1)) + (match_dup 2)) + (match_dup 3))) + (clobber (reg:SI T_REG))])]) + +;; Canonicalize '2 * reg + (reg & 1)' into 'reg + reg + (reg & 1)'. +(define_insn_and_split "*addc_2r_lsb" + [(set (match_operand:SI 0 "arith_reg_dest") + (plus:SI (and:SI (match_operand:SI 1 "arith_reg_operand") + (const_int 1)) + (mult:SI (match_operand:SI 2 "arith_reg_operand") + (const_int 2)))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& can_create_pseudo_p ()" + [(parallel [(set (match_dup 0) + (plus:SI (plus:SI (and:SI (match_dup 1) (const_int 1)) + (match_dup 2)) + (match_dup 2))) + (clobber (reg:SI T_REG))])]) + +;; Use shll-addc to do 'reg + ((unsigned int)reg >> 31)'. +(define_insn_and_split "*addc_r_msb" + [(set (match_operand:SI 0 "arith_reg_dest") + (plus:SI (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand") + (const_int 31)) + (match_operand:SI 2 "arith_reg_operand"))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& can_create_pseudo_p ()" + [(parallel [(set (match_dup 0) (plus:SI (reg:SI T_REG) (match_dup 2))) + (clobber (reg:SI T_REG))])] +{ + emit_insn (gen_shll (gen_reg_rtx (SImode), operands[1])); +}) + +;; Use shll-addc to do 'reg + reg + ((unsigned int)reg >> 31)'. +(define_insn_and_split "*addc_r_r_msb" + [(set (match_operand:SI 0 "arith_reg_dest") + (plus:SI (plus:SI (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand") + (const_int 31)) + (match_operand:SI 2 "arith_reg_operand")) + (match_operand:SI 3 "arith_reg_operand"))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& can_create_pseudo_p ()" + [(parallel [(set (match_dup 0) (plus:SI (plus:SI (match_dup 2) (match_dup 3)) + (reg:SI T_REG))) + (clobber (reg:SI T_REG))])] +{ + emit_insn (gen_shll (gen_reg_rtx (SImode), operands[1])); +}) + +;; Canonicalize '2 * reg + ((unsigned int)reg >> 31)' +;; into 'reg + reg + (reg & 1)'. +(define_insn_and_split "*addc_2r_msb" + [(set (match_operand:SI 0 "arith_reg_dest") + (plus:SI (mult:SI (match_operand:SI 1 "arith_reg_operand") + (const_int 2)) + (lshiftrt:SI (match_operand:SI 2 "arith_reg_operand") + (const_int 31)))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& can_create_pseudo_p ()" + [(parallel [(set (match_dup 0) + (plus:SI (plus:SI (lshiftrt:SI (match_dup 2) (const_int 31)) + (match_dup 1)) + (match_dup 1))) + (clobber (reg:SI T_REG))])]) + (define_expand "addsi3" [(set (match_operand:SI 0 "arith_reg_operand" "") (plus:SI (match_operand:SI 1 "arith_operand" "") diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3dfbac7a77b0..0f5f02b8c045 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2013-10-29 Oleg Endo + + PR target/54236 + * gcc.target/sh/pr54236-2: New. + * gcc.target/sh/pr54089-6: Add another rotl special case. + 2013-10-29 Paul Thomas PR fortran 58793 diff --git a/gcc/testsuite/gcc.target/sh/pr54089-6.c b/gcc/testsuite/gcc.target/sh/pr54089-6.c index a12a0e93044c..629a76441864 100644 --- a/gcc/testsuite/gcc.target/sh/pr54089-6.c +++ b/gcc/testsuite/gcc.target/sh/pr54089-6.c @@ -3,7 +3,7 @@ /* { dg-options "-O1" } */ /* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */ /* { dg-final { scan-assembler-times "rotr" 2 } } */ -/* { dg-final { scan-assembler-times "rotl" 2 } } */ +/* { dg-final { scan-assembler-times "rotl" 3 } } */ int test_00 (int a) @@ -28,3 +28,9 @@ test_03 (int a) { return ((a >> 1) & 0x7FFFFFFF) | (a << 31); } + +int +test_04 (int a) +{ + return a + a + ((a >> 31) & 1); +} diff --git a/gcc/testsuite/gcc.target/sh/pr54236-2.c b/gcc/testsuite/gcc.target/sh/pr54236-2.c new file mode 100644 index 000000000000..afcd33817c69 --- /dev/null +++ b/gcc/testsuite/gcc.target/sh/pr54236-2.c @@ -0,0 +1,270 @@ +/* Tests to check the utilization of the addc instruction in special cases. + If everything works as expected we won't see any movt instructions in + these cases. */ +/* { dg-do compile { target "sh*-*-*" } } */ +/* { dg-options "-O1" } */ +/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */ +/* { dg-final { scan-assembler-times "addc" 37 } } */ +/* { dg-final { scan-assembler-times "shlr" 23 } } */ +/* { dg-final { scan-assembler-times "shll" 14 } } */ +/* { dg-final { scan-assembler-times "add\t" 12 } } */ +/* { dg-final { scan-assembler-not "movt" } } */ + +int +test_000 (int a, int c, int b, int d) +{ + // 1x shlr, 1x addc + return a + (b & 1); +} + +int +test_001 (int a, int c, int b, int d) +{ + // 1x shlr, 1x addc + return a + b + (c & 1); +} + +int +test_002 (int a, int c, int b, int d) +{ + // 1x shlr, 1x add, 1x addc + return a + b + c + (d & 1); +} + +int +test_003 (int a, int c, int b, int d) +{ + // 1x shlr, 1x addc + return (b & 1) + a; +} + +int +test_004 (int a, int c, int b, int d) +{ + // 1x shlr, 1x addc + return a + (c & 1) + b; +} + +int +test_005 (int a, int c, int b, int d) +{ + // 1x shlr, 1x add, 1x addc + return a + b + (d & 1) + c; +} + +int +test_006 (int a, int c, int b, int d) +{ + // 1x shlr, 1x addc + return (c & 1) + a + b; +} + +int +test_007 (int a, int c, int b, int d) +{ + // 1x shlr, 1x add, 1x addc + return a + (d & 1) + b + c; +} + +int +test_008 (int a, int c, int b, int d) +{ + // 1x shlr, 1x add, 1x addc + return (d & 1) + a + b + c; +} + +int +test_009 (int a, int c, int b, int d) +{ + // 1x shlr, 1x addc + return a + b + (b & 1); +} + +int +test_010 (int a, int c, int b, int d) +{ + // 1x shlr, 1x addc + return a + (b & 1) + b; +} + +int +test_011 (int a, int c, int b, int d) +{ + // 1x shlr, 1x addc + return (b & 1) + a + b; +} + +int +test_012 (int a, int c, int b, int d) +{ + // 1x shlr, 1x add, 1x addc + return a + b + d + (b & 1); +} + +int +test_013 (int a, int c, int b, int d) +{ + // 1x shlr, 1x add, 1x addc + return a + d + (b & 1) + b; +} + +int +test_014 (int a, int c, int b, int d) +{ + // 1x shlr, 1x add, 1x addc + return a + (b & 1) + d + b; +} + +int +test_015 (int a, int c, int b, int d) +{ + // 1x shlr, 1x add, 1x addc + return (b & 1) + a + d + b; +} + +int +test_016 (int a, int b, int c, int d) +{ + // 1x shlr, 1x addc + return a + (a & 1); +} + +int +test_017 (int a, int b, int c, int d) +{ + // 1x shlr, 1x addc + return a + a + (a & 1); +} + +int +test_018 (int a, int b, int c, int d) +{ + // 1x shlr, 1x addc + return a + (a & 1) + a; +} + +int +test_019 (int a, int b, int c, int d) +{ + // 1x shlr, 1x addc + return (a & 1) + a + a; +} + +int +test_020 (int a, int b, int c, int d) +{ + // 1x shlr, 1x addc + return b + b + (a & 1); +} + +int +test_021 (int a, int b, int c, int d) +{ + // 1x shlr, 1x addc + return b + (a & 1) + b; +} + +int +test_022 (int a, int b, int c, int d) +{ + // 1x shlr, 1x addc + return (a & 1) + b + b; +} + +int +test_023 (int a, int b, int c, int d) +{ + // 1x shll, 1x addc + return a + ((b >> 31) & 1); +} + +int +test_024 (int a, int b, int c, int d) +{ + // 1x shll, 1x addc + return ((b >> 31) & 1) + a; +} + +int +test_025 (int a, int b, int c, int d) +{ + // 1x shll, 1x addc + return ((a >> 31) & 1) + a; +} + +int +test_026 (int a, int b, int c, int d) +{ + // 1x shll, 1x addc + return a + ((a >> 31) & 1); +} + +int +test_027 (int a, int b, int c, int d) +{ + // 1x shll, 1x addc + return a + b + ((c >> 31) & 1); +} + +int +test_028 (int a, int b, int c, int d) +{ + // 1x shll, 1x addc + return a + ((c >> 31) & 1) + b; +} + +int +test_029 (int a, int b, int c, int d) +{ + // 1x shll, 1x addc + return ((c >> 31) & 1) + a + b; +} + +int +test_030 (int a, int b, int c, int d) +{ + // 1x shll, 1x addc, 1x add + return a + b + c + ((d >> 31) & 1); +} + +int +test_031 (int a, int b, int c, int d) +{ + // 1x shll, 1x addc, 1x add + return a + b + ((d >> 31) & 1) + c; +} + +int +test_032 (int a, int b, int c, int d) +{ + // 1x shll, 1x addc, 1x add + return a + ((d >> 31) & 1) + b + c; +} + +int +test_033 (int a, int b, int c, int d) +{ + // 1x shll, 1x addc, 1x add + return ((d >> 31) & 1) + a + b + c; +} + +int +test_034 (int a, int b, int c, int d) +{ + // 1x shll, 1x addc + return a + a + ((d >> 31) & 1); +} + +int +test_035 (int a, int b, int c, int d) +{ + // 1x shll, 1x addc + return a + ((d >> 31) & 1) + a; +} + +int +test_036 (int a, int b, int c, int d) +{ + // 1x shll, 1x addc + return ((d >> 31) & 1) + a + a; +}