diff options
author | Haochen Gui <guihaoc@gcc.gnu.org> | 2022-08-18 16:23:11 +0800 |
---|---|---|
committer | Haochen Gui <guihaoc@gcc.gnu.org> | 2022-08-18 16:33:21 +0800 |
commit | defa08a33672d200edbdd7f87ed7afa442249261 (patch) | |
tree | 35ff0127c13e38f9b89722c4e796e756ffff3727 | |
parent | 4645ce0d00b8e19ea4bbfcd0cef37e91dea3c9f4 (diff) | |
download | gcc-defa08a33672d200edbdd7f87ed7afa442249261.tar.gz |
rs6000: Add expand pattern for multiply-add (PR103109)
gcc/
PR target/103109
* config/rs6000/rs6000.md (<u>maddditi4): New pattern for multiply-add.
(<u>madddi4_highpart): New.
(<u>madddi4_highpart_le): New.
gcc/testsuite/
PR target/103109
* gcc.target/powerpc/pr103109.h: New.
* gcc.target/powerpc/pr103109-1.c: New.
* gcc.target/powerpc/pr103109-2.c: New.
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 48 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/powerpc/pr103109-1.c | 10 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/powerpc/pr103109-2.c | 96 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/powerpc/pr103109.h | 12 |
4 files changed, 165 insertions, 1 deletions
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 1367a2cb779..e9e5cd1e54d 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -3217,7 +3217,7 @@ DONE; }) -(define_insn "*maddld<mode>4" +(define_insn "maddld<mode>4" [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") (plus:GPR (mult:GPR (match_operand:GPR 1 "gpc_reg_operand" "r") (match_operand:GPR 2 "gpc_reg_operand" "r")) @@ -3226,6 +3226,52 @@ "maddld %0,%1,%2,%3" [(set_attr "type" "mul")]) +(define_expand "<u>maddditi4" + [(set (match_operand:TI 0 "gpc_reg_operand") + (plus:TI + (mult:TI (any_extend:TI (match_operand:DI 1 "gpc_reg_operand")) + (any_extend:TI (match_operand:DI 2 "gpc_reg_operand"))) + (any_extend:TI (match_operand:DI 3 "gpc_reg_operand"))))] + "TARGET_MADDLD && TARGET_POWERPC64" +{ + rtx op0_lo = gen_rtx_SUBREG (DImode, operands[0], BYTES_BIG_ENDIAN ? 8 : 0); + rtx op0_hi = gen_rtx_SUBREG (DImode, operands[0], BYTES_BIG_ENDIAN ? 0 : 8); + + emit_insn (gen_maddlddi4 (op0_lo, operands[1], operands[2], operands[3])); + + if (BYTES_BIG_ENDIAN) + emit_insn (gen_<u>madddi4_highpart (op0_hi, operands[1], operands[2], + operands[3])); + else + emit_insn (gen_<u>madddi4_highpart_le (op0_hi, operands[1], operands[2], + operands[3])); + DONE; +}) + +(define_insn "<u>madddi4_highpart" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (subreg:DI + (plus:TI + (mult:TI (any_extend:TI (match_operand:DI 1 "gpc_reg_operand" "r")) + (any_extend:TI (match_operand:DI 2 "gpc_reg_operand" "r"))) + (any_extend:TI (match_operand:DI 3 "gpc_reg_operand" "r"))) + 0))] + "TARGET_MADDLD && BYTES_BIG_ENDIAN && TARGET_POWERPC64" + "maddhd<u> %0,%1,%2,%3" + [(set_attr "type" "mul")]) + +(define_insn "<u>madddi4_highpart_le" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (subreg:DI + (plus:TI + (mult:TI (any_extend:TI (match_operand:DI 1 "gpc_reg_operand" "r")) + (any_extend:TI (match_operand:DI 2 "gpc_reg_operand" "r"))) + (any_extend:TI (match_operand:DI 3 "gpc_reg_operand" "r"))) + 8))] + "TARGET_MADDLD && !BYTES_BIG_ENDIAN && TARGET_POWERPC64" + "maddhd<u> %0,%1,%2,%3" + [(set_attr "type" "mul")]) + (define_insn "udiv<mode>3" [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") (udiv:GPR (match_operand:GPR 1 "gpc_reg_operand" "r") diff --git a/gcc/testsuite/gcc.target/powerpc/pr103109-1.c b/gcc/testsuite/gcc.target/powerpc/pr103109-1.c new file mode 100644 index 00000000000..097a44ea35d --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr103109-1.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mdejagnu-cpu=power9" } */ +/* { dg-require-effective-target int128 } */ +/* { dg-require-effective-target powerpc_p9modulo_ok } */ +/* { dg-require-effective-target has_arch_ppc64 } */ +/* { dg-final { scan-assembler-times {\mmaddld\M} 2 } } */ +/* { dg-final { scan-assembler-times {\mmaddhd\M} 1 } } */ +/* { dg-final { scan-assembler-times {\mmaddhdu\M} 1 } } */ + +#include "pr103109.h" diff --git a/gcc/testsuite/gcc.target/powerpc/pr103109-2.c b/gcc/testsuite/gcc.target/powerpc/pr103109-2.c new file mode 100644 index 00000000000..4b93519ec65 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr103109-2.c @@ -0,0 +1,96 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mdejagnu-cpu=power9" } */ +/* { dg-require-effective-target int128 } */ +/* { dg-require-effective-target p9modulo_hw } */ +/* { dg-require-effective-target has_arch_ppc64 } */ + +#include "pr103109.h" + +union U { + __int128 i128; + struct { + long l1; + long l2; + } s; +}; + +__int128 +create_i128 (long most_sig, long least_sig) +{ + union U u; + +#if __LITTLE_ENDIAN__ + u.s.l1 = least_sig; + u.s.l2 = most_sig; +#else + u.s.l1 = most_sig; + u.s.l2 = least_sig; +#endif + return u.i128; +} + +#define DEBUG 0 + +#if DEBUG +#include <stdio.h> +#include <stdlib.h> + +void print_i128(__int128 val, int unsignedp) +{ + if (unsignedp) + printf(" %llu ", (unsigned long long)(val >> 64)); + else + printf(" %lld ", (signed long long)(val >> 64)); + + printf("%llu (0x%llx %llx)", + (unsigned long long)(val & 0xFFFFFFFFFFFFFFFF), + (unsigned long long)(val >> 64), + (unsigned long long)(val & 0xFFFFFFFFFFFFFFFF)); +} +#endif + +void abort (void); + +int main () +{ + long a = 0xFEDCBA9876543210L; + long b = 0x1000000L; + long c = 0x123456L; + __int128 expected_result = create_i128 (0xFFFFFFFFFFFEDCBAL, + 0x9876543210123456L); + + __int128 result = multiply_add (a, b, c); + + if (result != expected_result) + { +#if DEBUG + printf ("ERROR: multiply_add (%lld, %lld, %lld) = ", a, b, c); + print_i128 (result, 0); + printf ("\n does not match expected_result = "); + print_i128 (expected_result, 0); + printf ("\n\n"); +#else + abort(); +#endif + } + + unsigned long au = 0xFEDCBA9876543210UL; + unsigned long bu = 0x1000000UL; + unsigned long cu = 0x123456UL; + unsigned __int128 expected_resultu = create_i128 (0x0000000000FEDCBAL, + 0x9876543210123456L); + + unsigned __int128 resultu = multiply_addu (au, bu, cu); + if (resultu != expected_resultu) + { +#if DEBUG + printf ("ERROR: multiply_addu (%llu, %llu, %llu) = ", au, bu, cu); + print_i128 (resultu, 1); + printf ("\n does not match expected_result = "); + print_i128 (expected_resultu, 1); + printf ("\n\n"); +#else + abort(); +#endif + } +} diff --git a/gcc/testsuite/gcc.target/powerpc/pr103109.h b/gcc/testsuite/gcc.target/powerpc/pr103109.h new file mode 100644 index 00000000000..d16a5dd5656 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr103109.h @@ -0,0 +1,12 @@ +__attribute__((noinline)) +__int128 multiply_add (long a, long b, long c) +{ + return (__int128) a * b + c; +} + +__attribute__((noinline)) +unsigned __int128 multiply_addu (unsigned long a, unsigned long b, + unsigned long c) +{ + return (unsigned __int128) a * b + c; +} |