From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by sourceware.org (Postfix) with ESMTP id 706DE3857C74 for ; Wed, 6 Oct 2021 14:19:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 706DE3857C74 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id E08EA6D; Wed, 6 Oct 2021 07:19:24 -0700 (PDT) Received: from localhost (e121540-lin.manchester.arm.com [10.32.98.126]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 4E9DC3F66F; Wed, 6 Oct 2021 07:19:24 -0700 (PDT) From: Richard Sandiford To: "Roger Sayle" Mail-Followup-To: "Roger Sayle" , "'GCC Patches'" , richard.sandiford@arm.com Cc: "'GCC Patches'" Subject: Re: [PATCH #2] Introduce smul_highpart and umul_highpart RTX for high-part multiplications References: <022c01d7b546$33034730$9909d590$@nextmovesoftware.com> Date: Wed, 06 Oct 2021 15:19:23 +0100 In-Reply-To: <022c01d7b546$33034730$9909d590$@nextmovesoftware.com> (Roger Sayle's message of "Wed, 29 Sep 2021 16:25:12 +0100") Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.3 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-12.3 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, KAM_SHORT, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 06 Oct 2021 14:19:28 -0000 "Roger Sayle" writes: > Hi Richard, > > All excellent suggestions. The revised patch below implements all of > your (and Andreas') recommendations. I'm happy to restrict GCC's support > for saturating arithmetic to integer types, even though I do know of one > target (nvptx) that supports saturating floating point math, where results > are clamped to [0.0, 1.0], but I've not investigated how NaNs or signed > zeros are handled. > > Good catch on my min/max typo. It convinced me to work harder to come > up with some test cases for these simplifications, which I've managed to > trigger on x86_64-pc-linux-gnu in the four new attached test cases. > > This patch has been tested on x86_64-pc-linux-gnu with "make bootstrap" > and "make -k check" with no new failures. Ok for mainline? > > 2021-09-29 Roger Sayle > Richard Sandiford Thanks for the cite, but I don't think I should be listed here. I didn't really write anything :-) The new patch is OK, thanks. I don't know whether the x86 tests need special markup. Richard > > gcc/ChangeLog > * gcc/rtl.def (SMUL_HIGHPART, UMUL_HIGHPART): New RTX codes for > representing signed and unsigned high-part multiplication resp. > * gcc/simplify-rtx.c (simplify_binary_operation_1) [SMUL_HIGHPART, > UMUL_HIGHPART]: Simplify high-part multiplications by zero. > [SS_PLUS, US_PLUS, SS_MINUS, US_MINUS, SS_MULT, US_MULT, > SS_DIV, US_DIV]: Similar simplifications for saturating > arithmetic. > (simplify_const_binary_operation) [SS_PLUS, US_PLUS, SS_MINUS, > US_MINUS, SS_MULT, US_MULT, SMUL_HIGHPART, UMUL_HIGHPART]: > Implement compile-time evaluation for constant operands. > > * gcc/dwarf2out.c (mem_loc_descriptor): Skip SMUL_HIGHPART and > UMUL_HIGHPART. > * doc/rtl.texi (smul_highpart, umul_highpart): Document RTX codes. > * doc/md.texi (smul@var{m}3_highpart, umul@var{m3}_highpart): > Mention the new smul_highpart and umul_highpart RTX codes. > * doc/invoke.texi: Silence @xref "compilation" warnings. > > gcc/testsuite/ChangeLog > * gcc.target/i386/sse2-mmx-paddsb-2.c: New test case. > * gcc.target/i386/sse2-mmx-paddusb-2.c: New test case. > * gcc.target/i386/sse2-mmx-subsb-2.c: New test case. > * gcc.target/i386/sse2-mmx-subusb-2.c: New test case. > > Roger > -- > > -----Original Message----- > From: Richard Sandiford =20 > Sent: 27 September 2021 16:44 > To: Roger Sayle > Cc: 'GCC Patches' > Subject: Re: [PATCH] Introduce sh_mul and uh_mul RTX codes for high-part = multiplications > > "Roger Sayle" writes: >> This patch introduces new RTX codes to allow the RTL passes and=20 >> backends to consistently represent high-part multiplications. >> Currently, the RTL used by different backends for expanding=20 >> smul3_highpart and umul3_highpart varies greatly, with=20 >> many but not all choosing to express this something like: >> >> (define_insn "smuldi3_highpart" >> [(set (match_operand:DI 0 "nvptx_register_operand" "=3DR") >> (truncate:DI >> (lshiftrt:TI >> (mult:TI (sign_extend:TI >> (match_operand:DI 1 "nvptx_register_operand" "R")) >> (sign_extend:TI >> (match_operand:DI 2 "nvptx_register_operand" "R"))) >> (const_int 64))))] >> "" >> "%.\\tmul.hi.s64\\t%0, %1, %2;") >> >> One complication with using this "widening multiplication"=20 >> representation is that it requires an intermediate in a wider mode,=20 >> making it difficult or impossible to encode a high-part multiplication=20 >> of the widest supported integer mode. > > Yeah. It's also a problem when representing vector ops. > >> A second is that it can interfere with optimization; for example=20 >> simplify-rtx.c contains the comment: >> >> case TRUNCATE: >> /* Don't optimize (lshiftrt (mult ...)) as it would interfere >> with the umulXi3_highpart patterns. */ >> >> Hopefully these problems are solved (or reduced) by introducing a new=20 >> canonical form for high-part multiplications in RTL passes. >> This also simplifies insn patterns when one operand is constant. >> >> Whilst implementing some constant folding simplifications and=20 >> compile-time evaluation of these new RTX codes, I noticed that this=20 >> functionality could also be added for the existing saturating=20 >> arithmetic RTX codes. Then likewise when documenting these new RTX=20 >> codes, I also took the opportunity to silence the @xref warnings in=20 >> invoke.texi. >> >> This patch has been tested on x86_64-pc-linux-gnu with "make bootstrap" >> and "make -k check" with no new failures. Ok for mainline? >> >> >> 2021-09-25 Roger Sayle >> >> gcc/ChangeLog >> * gcc/rtl.def (SH_MULT, UH_MULT): New RTX codes for representing >> signed and unsigned high-part multiplication respectively. >> * gcc/simplify-rtx.c (simplify_binary_operation_1) [SH_MULT, >> UH_MULT]: Simplify high-part multiplications by zero. >> [SS_PLUS, US_PLUS, SS_MINUS, US_MINUS, SS_MULT, US_MULT, >> SS_DIV, US_DIV]: Similar simplifications for saturating >> arithmetic. >> (simplify_const_binary_operation) [SS_PLUS, US_PLUS, SS_MINUS, >> US_MINUS, SS_MULT, US_MULT, SH_MULT, UH_MULT]: Implement >> compile-time evaluation for constant operands. >> * gcc/dwarf2out.c (mem_loc_descriptor): Skip SH_MULT and UH_MULT. >> * doc/rtl.texi (sh_mult, uhmult): Document new RTX codes. >> * doc/md.texi (smul@var{m}3_highpart, umul@var{m3}_highpart): >> Mention the new sh_mul and uh_mul RTX codes. >> * doc/invoke.texi: Silence @xref "compilation" warnings. > > Look like a good idea to me. Only real comment is on the naming: > if possible, I think we should try to avoid introducing yet more differen= ces between optab names and rtl codes. How about umul_highpart for the uns= igned code, to match both the optab and the existing convention of adding = =E2=80=9Cu=E2=80=9D directly to the front of non-saturating operations? > > Things are more inconsistent for signed rtx codes: sometimes the =E2=80= =9Cs=E2=80=9D is present and sometimes it isn't. But since =E2=80=9Csmin= =E2=80=9D and =E2=80=9Csmax=E2=80=9D > have it, I think we can justify having it here too. > > So I think we should use smul_highpart and umul_highpart. > It's a bit more wordy than sh_mul, but still a lot shorter than the statu= s quo ;-) > >> diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index=20 >> ebad5cb..b4b04b9 100644 >> --- a/gcc/simplify-rtx.c >> +++ b/gcc/simplify-rtx.c >> @@ -4142,11 +4142,40 @@ simplify_context::simplify_binary_operation_1 (r= tx_code code, >> case US_PLUS: >> case SS_MINUS: >> case US_MINUS: >> + /* Simplify x + 0 to x, if possible. */ > > Nit: +/- > >> + if (trueop1 =3D=3D CONST0_RTX (mode) && !HONOR_SIGNED_ZEROS (mode= )) > > The HONOR_SIGNED_ZEROS check is redundant, since these ops don't support = modes with signed zero. > > Same for the other HONOR_* macros in the patch. E.g. I don't think we sh= ould try to guess how infinities and saturation work together. > >> + return op0; >> + return 0; >> + >> case SS_MULT: >> case US_MULT: >> + /* Simplify x * 0 to 0, if possible. */ >> + if (trueop1 =3D=3D CONST0_RTX (mode) >> + && !HONOR_NANS (mode) >> + && !HONOR_SIGNED_ZEROS (mode) >> + && !side_effects_p (op0)) >> + return op1; >> + >> + /* Simplify x * 1 to x, if possible. */ >> + if (trueop1 =3D=3D CONST1_RTX (mode) && !HONOR_SNANS (mode)) >> + return op0; >> + return 0; >> + >> + case SH_MULT: >> + case UH_MULT: >> + /* Simplify x * 0 to 0, if possible. */ >> + if (trueop1 =3D=3D CONST0_RTX (mode) >> + && !HONOR_NANS (mode) >> + && !HONOR_SIGNED_ZEROS (mode) >> + && !side_effects_p (op0)) >> + return op1; >> + return 0; >> + >> case SS_DIV: >> case US_DIV: >> - /* ??? There are simplifications that can be done. */ >> + /* Simplify x / 1 to x, if possible. */ >> + if (trueop1 =3D=3D CONST1_RTX (mode) && !HONOR_SNANS (mode)) >> + return op0; >> return 0; >>=20=20 >> case VEC_SERIES: >> @@ -5011,6 +5040,63 @@ simplify_const_binary_operation (enum rtx_code co= de, machine_mode mode, >> } >> break; >> } >> + >> + case SS_PLUS: >> + result =3D wi::add (pop0, pop1, SIGNED, &overflow); > > I think a goto label would be good here, so that later signed ops can reu= se this code instead of having to repeat it. > Same idea for the unsigned case. > >> + if (overflow =3D=3D wi::OVF_OVERFLOW) >> + result =3D wi::max_value (GET_MODE_PRECISION (int_mode), SIGNED); >> + else if (overflow =3D=3D wi::OVF_UNDERFLOW) >> + result =3D wi::max_value (GET_MODE_PRECISION (int_mode), SIGNED); > > Should be min_value. Same for the other underflow handlers. > > Like Andreas said, @pxref would be better where applicable. > > Thanks, > Richard > >> + else if (overflow !=3D wi::OVF_NONE) >> + return NULL_RTX; >> + break; >> + >> + case US_PLUS: >> + result =3D wi::add (pop0, pop1, UNSIGNED, &overflow); >> + if (overflow !=3D wi::OVF_NONE) >> + result =3D wi::max_value (GET_MODE_PRECISION (int_mode), UNSIGNED); >> + break; >> + >> + case SS_MINUS: >> + result =3D wi::sub (pop0, pop1, SIGNED, &overflow); >> + if (overflow =3D=3D wi::OVF_OVERFLOW) >> + result =3D wi::max_value (GET_MODE_PRECISION (int_mode), SIGNED); >> + else if (overflow =3D=3D wi::OVF_UNDERFLOW) >> + result =3D wi::max_value (GET_MODE_PRECISION (int_mode), SIGNED); >> + else if (overflow !=3D wi::OVF_NONE) >> + return NULL_RTX; >> + break; >> + >> + case US_MINUS: >> + result =3D wi::sub (pop0, pop1, UNSIGNED, &overflow); >> + if (overflow !=3D wi::OVF_NONE) >> + result =3D wi::min_value (GET_MODE_PRECISION (int_mode), UNSIGNED); >> + break; >> + >> + case SS_MULT: >> + result =3D wi::mul (pop0, pop1, SIGNED, &overflow); >> + if (overflow =3D=3D wi::OVF_OVERFLOW) >> + result =3D wi::max_value (GET_MODE_PRECISION (int_mode), SIGNED); >> + else if (overflow =3D=3D wi::OVF_UNDERFLOW) >> + result =3D wi::max_value (GET_MODE_PRECISION (int_mode), SIGNED); >> + else if (overflow !=3D wi::OVF_NONE) >> + return NULL_RTX; >> + break; >> + >> + case US_MULT: >> + result =3D wi::mul (pop0, pop1, UNSIGNED, &overflow); >> + if (overflow !=3D wi::OVF_NONE) >> + result =3D wi::max_value (GET_MODE_PRECISION (int_mode), UNSIGNED); >> + break; >> + >> + case SH_MULT: >> + result =3D wi::mul_high (pop0, pop1, SIGNED); >> + break; >> + >> + case UH_MULT: >> + result =3D wi::mul_high (pop0, pop1, UNSIGNED); >> + break; >> + >> default: >> return NULL_RTX; >> } > > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index 4acb941..7ed0c69 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -3125,7 +3125,7 @@ errors if these functions are not inlined everywher= e they are called. > @itemx -fno-modules-ts > @opindex fmodules-ts > @opindex fno-modules-ts > -Enable support for C++20 modules (@xref{C++ Modules}). The > +Enable support for C++20 modules (@pxref{C++ Modules}). The > @option{-fno-modules-ts} is usually not needed, as that is the > default. Even though this is a C++20 feature, it is not currently > implicitly enabled by selecting that standard version. > @@ -33553,7 +33553,7 @@ version selected, although in pre-C++20 versions,= it is of course an > extension. >=20=20 > No new source file suffixes are required or supported. If you wish to > -use a non-standard suffix (@xref{Overall Options}), you also need > +use a non-standard suffix (@pxref{Overall Options}), you also need > to provide a @option{-x c++} option too.@footnote{Some users like to > distinguish module interface files with a new suffix, such as naming > the source @code{module.cppm}, which involves > @@ -33615,8 +33615,8 @@ to be resolved at the end of compilation. Withou= t this, imported > macros are only resolved when expanded or (re)defined. This option > detects conflicting import definitions for all macros. >=20=20 > -@xref{C++ Module Mapper} for details of the @option{-fmodule-mapper} > -family of options. > +For details of the @option{-fmodule-mapper} family of options, > +@pxref{C++ Module Mapper}. >=20=20 > @menu > * C++ Module Mapper:: Module Mapper > @@ -33833,8 +33833,8 @@ dialect used and imports of the module.@footnote{= The precise contents > of this output may change.} The timestamp is the same value as that > provided by the @code{__DATE__} & @code{__TIME__} macros, and may be > explicitly specified with the environment variable > -@code{SOURCE_DATE_EPOCH}. @xref{Environment Variables} for further > -details. > +@code{SOURCE_DATE_EPOCH}. For further details > +@pxref{Environment Variables}. >=20=20 > A set of related CMIs may be copied, provided the relative pathnames > are preserved. > diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi > index 2b41cb7..ed35b8f 100644 > --- a/gcc/doc/md.texi > +++ b/gcc/doc/md.texi > @@ -5776,11 +5776,13 @@ multiplication. > @item @samp{smul@var{m}3_highpart} > Perform a signed multiplication of operands 1 and 2, which have mode > @var{m}, and store the most significant half of the product in operand 0. > -The least significant half of the product is discarded. > +The least significant half of the product is discarded. This may be > +represented in RTL using a @code{smul_highpart} RTX expression. >=20=20 > @cindex @code{umul@var{m}3_highpart} instruction pattern > @item @samp{umul@var{m}3_highpart} > -Similar, but the multiplication is unsigned. > +Similar, but the multiplication is unsigned. This may be represented > +in RTL using an @code{umul_highpart} RTX expression. >=20=20 > @cindex @code{madd@var{m}@var{n}4} instruction pattern > @item @samp{madd@var{m}@var{n}4} > diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi > index e1e76a9..2058997 100644 > --- a/gcc/doc/rtl.texi > +++ b/gcc/doc/rtl.texi > @@ -2524,7 +2524,19 @@ not be the same. > For unsigned widening multiplication, use the same idiom, but with > @code{zero_extend} instead of @code{sign_extend}. >=20=20 > +@findex smul_highpart > +@findex umul_highpart > +@cindex high-part multiplication > +@cindex multiplication high part > +@item (smul_highpart:@var{m} @var{x} @var{y}) > +@itemx (umul_highpart:@var{m} @var{x} @var{y}) > +Represents the high-part multiplication of @var{x} and @var{y} carried > +out in machine mode @var{m}. @code{smul_highpart} returns the high part > +of a signed multiplication, @code{umul_highpart} returns the high part > +of an unsigned multiplication. > + > @findex fma > +@cindex fused multiply-add > @item (fma:@var{m} @var{x} @var{y} @var{z}) > Represents the @code{fma}, @code{fmaf}, and @code{fmal} builtin > functions, which compute @samp{@var{x} * @var{y} + @var{z}} > diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c > index 9876750..20f2c5d 100644 > --- a/gcc/dwarf2out.c > +++ b/gcc/dwarf2out.c > @@ -16809,6 +16809,8 @@ mem_loc_descriptor (rtx rtl, machine_mode mode, > case CONST_FIXED: > case CLRSB: > case CLOBBER: > + case SMUL_HIGHPART: > + case UMUL_HIGHPART: > break; >=20=20 > case CONST_STRING: > diff --git a/gcc/rtl.def b/gcc/rtl.def > index c80144b..5710a2e 100644 > --- a/gcc/rtl.def > +++ b/gcc/rtl.def > @@ -467,6 +467,11 @@ DEF_RTL_EXPR(SS_MULT, "ss_mult", "ee", RTX_COMM_ARIT= H) > /* Multiplication with unsigned saturation */ > DEF_RTL_EXPR(US_MULT, "us_mult", "ee", RTX_COMM_ARITH) >=20=20 > +/* Signed high-part multiplication. */ > +DEF_RTL_EXPR(SMUL_HIGHPART, "smul_highpart", "ee", RTX_COMM_ARITH) > +/* Unsigned high-part multiplication. */ > +DEF_RTL_EXPR(UMUL_HIGHPART, "umul_highpart", "ee", RTX_COMM_ARITH) > + > /* Operand 0 divided by operand 1. */ > DEF_RTL_EXPR(DIV, "div", "ee", RTX_BIN_ARITH) > /* Division with signed saturation */ > diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c > index ebad5cb..7e8e2c3 100644 > --- a/gcc/simplify-rtx.c > +++ b/gcc/simplify-rtx.c > @@ -4142,11 +4142,36 @@ simplify_context::simplify_binary_operation_1 (rt= x_code code, > case US_PLUS: > case SS_MINUS: > case US_MINUS: > + /* Simplify x +/- 0 to x, if possible. */ > + if (trueop1 =3D=3D CONST0_RTX (mode)) > + return op0; > + return 0; > + > case SS_MULT: > case US_MULT: > + /* Simplify x * 0 to 0, if possible. */ > + if (trueop1 =3D=3D CONST0_RTX (mode) > + && !side_effects_p (op0)) > + return op1; > + > + /* Simplify x * 1 to x, if possible. */ > + if (trueop1 =3D=3D CONST1_RTX (mode)) > + return op0; > + return 0; > + > + case SMUL_HIGHPART: > + case UMUL_HIGHPART: > + /* Simplify x * 0 to 0, if possible. */ > + if (trueop1 =3D=3D CONST0_RTX (mode) > + && !side_effects_p (op0)) > + return op1; > + return 0; > + > case SS_DIV: > case US_DIV: > - /* ??? There are simplifications that can be done. */ > + /* Simplify x / 1 to x, if possible. */ > + if (trueop1 =3D=3D CONST1_RTX (mode)) > + return op0; > return 0; >=20=20 > case VEC_SERIES: > @@ -5011,6 +5036,51 @@ simplify_const_binary_operation (enum rtx_code cod= e, machine_mode mode, > } > break; > } > + > + case SS_PLUS: > + result =3D wi::add (pop0, pop1, SIGNED, &overflow); > + clamp_signed_saturation: > + if (overflow =3D=3D wi::OVF_OVERFLOW) > + result =3D wi::max_value (GET_MODE_PRECISION (int_mode), SIGNED); > + else if (overflow =3D=3D wi::OVF_UNDERFLOW) > + result =3D wi::min_value (GET_MODE_PRECISION (int_mode), SIGNED); > + else if (overflow !=3D wi::OVF_NONE) > + return NULL_RTX; > + break; > + > + case US_PLUS: > + result =3D wi::add (pop0, pop1, UNSIGNED, &overflow); > + clamp_unsigned_saturation:=20 > + if (overflow !=3D wi::OVF_NONE) > + result =3D wi::max_value (GET_MODE_PRECISION (int_mode), UNSIGNED); > + break; > + > + case SS_MINUS: > + result =3D wi::sub (pop0, pop1, SIGNED, &overflow); > + goto clamp_signed_saturation; > + > + case US_MINUS: > + result =3D wi::sub (pop0, pop1, UNSIGNED, &overflow); > + if (overflow !=3D wi::OVF_NONE) > + result =3D wi::min_value (GET_MODE_PRECISION (int_mode), UNSIGNED); > + break; > + > + case SS_MULT: > + result =3D wi::mul (pop0, pop1, SIGNED, &overflow); > + goto clamp_signed_saturation; > + > + case US_MULT: > + result =3D wi::mul (pop0, pop1, UNSIGNED, &overflow); > + goto clamp_unsigned_saturation; > + > + case SMUL_HIGHPART: > + result =3D wi::mul_high (pop0, pop1, SIGNED); > + break; > + > + case UMUL_HIGHPART: > + result =3D wi::mul_high (pop0, pop1, UNSIGNED); > + break; > + > default: > return NULL_RTX; > } > > /* { dg-do compile } */ > /* { dg-options "-O2" } */ > > typedef char v8qi __attribute__ ((vector_size (8))); > > char foo() > { > v8qi tx =3D { 1, 0, 0, 0, 0, 0, 0, 0 }; > v8qi ty =3D { 2, 0, 0, 0, 0, 0, 0, 0 }; > v8qi t =3D __builtin_ia32_paddsb(tx, ty); > return t[0]; > } > > char bar() > { > v8qi tx =3D { 100, 0, 0, 0, 0, 0, 0, 0 }; > v8qi ty =3D { 100, 0, 0, 0, 0, 0, 0, 0 }; > v8qi t =3D __builtin_ia32_paddsb(tx, ty); > return t[0]; > } > > char baz() > { > v8qi tx =3D { -100, 0, 0, 0, 0, 0, 0, 0 }; > v8qi ty =3D { -100, 0, 0, 0, 0, 0, 0, 0 }; > v8qi t =3D __builtin_ia32_paddsb(tx, ty); > return t[0]; > } > > /* { dg-final { scan-assembler-times "movl\[ \\t\]+\\\$3," 1 } } */ > /* { dg-final { scan-assembler-times "movl\[ \\t\]+\\\$127," 1 } } */ > /* { dg-final { scan-assembler-times "movl\[ \\t\]+\\\$-128," 1 } } */ > /* { dg-final { scan-assembler-not "paddsb\[ \\t\]+%xmm\[0-9\]+" } } */ > > > > /* { dg-do compile } */ > /* { dg-options "-O2" } */ > > typedef char v8qi __attribute__ ((vector_size (8))); > > char foo() > { > v8qi tx =3D { 5, 0, 0, 0, 0, 0, 0, 0 }; > v8qi ty =3D { 2, 0, 0, 0, 0, 0, 0, 0 }; > v8qi t =3D __builtin_ia32_psubusb(tx, ty); > return t[0]; > } > > char bar() > { > v8qi tx =3D { 100, 0, 0, 0, 0, 0, 0, 0 }; > v8qi ty =3D { 200, 0, 0, 0, 0, 0, 0, 0 }; > v8qi t =3D __builtin_ia32_psubusb(tx, ty); > return t[0]; > } > > /* { dg-final { scan-assembler-times "movl\[ \\t\]+\\\$3," 1 } } */ > /* { dg-final { scan-assembler-times "xorl\[ \\t\]+" 1 } } */ > /* { dg-final { scan-assembler-not "psubusb\[ \\t\]+%xmm\[0-9\]+" } } */