Hi, This patch adds an expand and several insns for multiply-add with three 64bit operands.
Bootstrapped and tested on powerpc64-linux BE and LE with no regressions. Is this okay for trunk? Any recommendations? Thanks a lot. ChangeLog 2022-07-22 Haochen Gui <[email protected]> gcc/ PR target/103109 * config/rs6000/rs6000.md (<u>maddditi4): New pattern for multiply-add. (<u>madddi4_lowpart): New. (<u>madddi4_lowpart_le): New. (<u>madddi4_highpart): New. (<u>madddi4_highpart_le): New. gcc/testsuite/ PR target/103109 * gcc.target/powerpc/pr103109.c: New. patch.diff diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index c55ee7e171a..4f3b56e103e 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -3226,6 +3226,97 @@ (define_insn "*maddld<mode>4" "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_POWERPC64 && TARGET_MADDLD" +{ + 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); + + if (BYTES_BIG_ENDIAN) + { + emit_insn (gen_<u>madddi4_lowpart (op0_lo, operands[1], operands[2], + operands[3])); + emit_insn (gen_<u>madddi4_highpart (op0_hi, operands[1], operands[2], + operands[3])); + } + else + { + emit_insn (gen_<u>madddi4_lowpart_le (op0_lo, operands[1], operands[2], + operands[3])); + emit_insn (gen_<u>madddi4_highpart_le (op0_hi, operands[1], operands[2], + operands[3])); + } + DONE; +}) + +(define_insn "<u>madddi4_lowpart" + [(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_POWERPC64 && TARGET_MADDLD && BYTES_BIG_ENDIAN" + "maddld %0,%1,%2,%3" + [(set_attr "type" "mul")]) + +(define_insn "<u>madddi4_lowpart_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"))) + 0))] + "TARGET_POWERPC64 && TARGET_MADDLD && !BYTES_BIG_ENDIAN" + "maddld %0,%1,%2,%3" + [(set_attr "type" "mul")]) + +(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_POWERPC64 && TARGET_MADDLD && BYTES_BIG_ENDIAN" + "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_POWERPC64 && TARGET_MADDLD && !BYTES_BIG_ENDIAN" + "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.c b/gcc/testsuite/gcc.target/powerpc/pr103109.c new file mode 100644 index 00000000000..256e05d5677 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr103109.c @@ -0,0 +1,16 @@ +/* { dg-do compile { target { lp64 } } } */ +/* { dg-require-effective-target powerpc_p9modulo_ok } */ +/* { dg-options "-mdejagnu-cpu=power9 -O2" } */ +/* { dg-final { scan-assembler-times {\mmaddld\M} 2 } } */ +/* { dg-final { scan-assembler-times {\mmaddhd\M} 1 } } */ +/* { dg-final { scan-assembler-times {\mmaddhdu\M} 1 } } */ + +__int128 test (long a, long b, long c) +{ + return (__int128) a * (__int128) b + (__int128) c; +} + +unsigned __int128 testu (unsigned long a, unsigned long b, unsigned long c) +{ + return (unsigned __int128) a * (unsigned __int128) b + (unsigned __int128) c; +}
