diff options
author | Jakub Jelinek <jakub@redhat.com> | 2023-06-16 19:47:28 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2023-06-16 19:47:28 +0200 |
commit | 2b4e0415ad664cdb3ce87d1f7eee5ca26911a05b (patch) | |
tree | 899721fe206660eca7d72307acf6107606613c05 /gcc/doc/extend.texi | |
parent | 5b67116a85298bbe358b036d34ad23119cebbdac (diff) | |
download | gcc-2b4e0415ad664cdb3ce87d1f7eee5ca26911a05b.zip gcc-2b4e0415ad664cdb3ce87d1f7eee5ca26911a05b.tar.gz gcc-2b4e0415ad664cdb3ce87d1f7eee5ca26911a05b.tar.bz2 |
uiltins: Add support for clang compatible __builtin_{add,sub}c{,l,ll} [PR79173]
While the design of these builtins in clang is questionable,
rather than being say
unsigned __builtin_addc (unsigned, unsigned, bool, bool *)
so that it is clear they add two [0, 0xffffffff] range numbers
plus one [0, 1] range carry in and give [0, 0xffffffff] range
return plus [0, 1] range carry out, they actually instead
add 3 [0, 0xffffffff] values together but the carry out
isn't then the expected [0, 2] value because
0xffffffffULL + 0xffffffff + 0xffffffff is 0x2fffffffd,
but just [0, 1] whether there was any overflow at all.
It is something used in the wild and shorter to write than the
corresponding
#define __builtin_addc(a,b,carry_in,carry_out) \
({ unsigned _s; \
unsigned _c1 = __builtin_uadd_overflow (a, b, &_s); \
unsigned _c2 = __builtin_uadd_overflow (_s, carry_in, &_s); \
*(carry_out) = (_c1 | _c2); \
_s; })
and so a canned builtin for something people could often use.
It isn't that hard to maintain on the GCC side, as we just lower
it to two .ADD_OVERFLOW calls early, and the already committed
pottern recognization code can then make .UADDC/.USUBC calls out of
that if the carry in is in [0, 1] range and the corresponding
optab is supported by the target.
2023-06-16 Jakub Jelinek <jakub@redhat.com>
PR middle-end/79173
* builtin-types.def (BT_FN_UINT_UINT_UINT_UINT_UINTPTR,
BT_FN_ULONG_ULONG_ULONG_ULONG_ULONGPTR,
BT_FN_ULONGLONG_ULONGLONG_ULONGLONG_ULONGLONG_ULONGLONGPTR): New
types.
* builtins.def (BUILT_IN_ADDC, BUILT_IN_ADDCL, BUILT_IN_ADDCLL,
BUILT_IN_SUBC, BUILT_IN_SUBCL, BUILT_IN_SUBCLL): New builtins.
* builtins.cc (fold_builtin_addc_subc): New function.
(fold_builtin_varargs): Handle BUILT_IN_{ADD,SUB}C{,L,LL}.
* doc/extend.texi (__builtin_addc, __builtin_subc): Document.
* gcc.target/i386/pr79173-11.c: New test.
* gcc.dg/builtin-addc-1.c: New test.
Diffstat (limited to 'gcc/doc/extend.texi')
-rw-r--r-- | gcc/doc/extend.texi | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index e01e244..c01cd3f 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -12839,6 +12839,50 @@ after addition, conditional jump on carry etc. @enddefbuiltin +@defbuiltin{unsigned int __builtin_addc (unsigned int a, unsigned int b, unsigned int carry_in, unsigned int *carry_out)} +@defbuiltinx{unsigned long int __builtin_addcl (unsigned long int a, unsigned long int b, unsigned int carry_in, unsigned long int *carry_out)} +@defbuiltinx{unsigned long long int __builtin_addcll (unsigned long long int a, unsigned long long int b, unsigned long long int carry_in, unsigned long long int *carry_out)} + +These built-in functions are equivalent to: +@smallexample + (@{ __typeof__ (@var{a}) s; \ + __typeof__ (@var{a}) c1 = __builtin_add_overflow (@var{a}, @var{b}, &s); \ + __typeof__ (@var{a}) c2 = __builtin_add_overflow (s, @var{carry_in}, &s); \ + *(@var{carry_out}) = c1 | c2; \ + s; @}) +@end smallexample + +i.e.@: they add 3 unsigned values, set what the last argument +points to to 1 if any of the two additions overflowed (otherwise 0) +and return the sum of those 3 unsigned values. Note, while all +the first 3 arguments can have arbitrary values, better code will be +emitted if one of them (preferrably the third one) has only values +0 or 1 (i.e.@: carry-in). + +@enddefbuiltin + +@defbuiltin{unsigned int __builtin_subc (unsigned int a, unsigned int b, unsigned int carry_in, unsigned int *carry_out)} +@defbuiltinx{unsigned long int __builtin_subcl (unsigned long int a, unsigned long int b, unsigned int carry_in, unsigned long int *carry_out)} +@defbuiltinx{unsigned long long int __builtin_subcll (unsigned long long int a, unsigned long long int b, unsigned long long int carry_in, unsigned long long int *carry_out)} + +These built-in functions are equivalent to: +@smallexample + (@{ __typeof__ (@var{a}) s; \ + __typeof__ (@var{a}) c1 = __builtin_sub_overflow (@var{a}, @var{b}, &s); \ + __typeof__ (@var{a}) c2 = __builtin_sub_overflow (s, @var{carry_in}, &s); \ + *(@var{carry_out}) = c1 | c2; \ + s; @}) +@end smallexample + +i.e.@: they subtract 2 unsigned values from the first unsigned value, +set what the last argument points to to 1 if any of the two subtractions +overflowed (otherwise 0) and return the result of the subtractions. +Note, while all the first 3 arguments can have arbitrary values, better code +will be emitted if one of them (preferrably the third one) has only values +0 or 1 (i.e.@: carry-in). + +@enddefbuiltin + @node x86 specific memory model extensions for transactional memory @section x86-Specific Memory Model Extensions for Transactional Memory |