Hello, This adds some more patterns to utilize the SH addc instruction. Tested on rev 204111 with make -k check RUNTESTFLAGS="--target_board=sh-sim \{-m2a/-mb,-m2a-single/-mb,-m4/-ml,-m4-single/-ml,-m4/-mb,-m4-single/-mb}"
and no new failures. OK for trunk? Cheers, Oleg gcc/ChangeLog: PR target/54236 * config/sh/sh.md (*addc): Add more addc related insn and splits. * config/sh/sh.c (addsubcosts): Handle some addc special cases. testsuite/ChangeLog: PR target/54236 * gcc.target/sh/pr54236-2: New. * gcc.target/sh/pr54089-6: Add another rotl special case.
Index: gcc/config/sh/sh.md =================================================================== --- gcc/config/sh/sh.md (revision 204098) +++ gcc/config/sh/sh.md (working copy) @@ -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" + [(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" + [(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" + [(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" + [(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" + [(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" + [(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" + [(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" "") Index: gcc/config/sh/sh.c =================================================================== --- gcc/config/sh/sh.c (revision 204096) +++ gcc/config/sh/sh.c (working copy) @@ -3162,6 +3162,35 @@ 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 Index: gcc/testsuite/gcc.target/sh/pr54236-2.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr54236-2.c (revision 0) +++ gcc/testsuite/gcc.target/sh/pr54236-2.c (revision 0) @@ -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; +} Index: gcc/testsuite/gcc.target/sh/pr54089-6.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr54089-6.c (revision 204096) +++ gcc/testsuite/gcc.target/sh/pr54089-6.c (working copy) @@ -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 @@ { return ((a >> 1) & 0x7FFFFFFF) | (a << 31); } + +int +test_04 (int a) +{ + return a + a + ((a >> 31) & 1); +}