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.
This commit is contained in:
Haochen Gui 2022-08-18 16:23:11 +08:00
parent 4645ce0d00
commit defa08a336
4 changed files with 165 additions and 1 deletions

View file

@ -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")

View file

@ -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"

View file

@ -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
}
}

View file

@ -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;
}