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/builtins.cc | |
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/builtins.cc')
-rw-r--r-- | gcc/builtins.cc | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/gcc/builtins.cc b/gcc/builtins.cc index 8400ada..6dff521 100644 --- a/gcc/builtins.cc +++ b/gcc/builtins.cc @@ -9555,6 +9555,51 @@ fold_builtin_arith_overflow (location_t loc, enum built_in_function fcode, return build2_loc (loc, COMPOUND_EXPR, boolean_type_node, store, ovfres); } +/* Fold __builtin_{add,sub}c{,l,ll} into pair of internal functions + that return both result of arithmetics and overflowed boolean + flag in a complex integer result. */ + +static tree +fold_builtin_addc_subc (location_t loc, enum built_in_function fcode, + tree *args) +{ + enum internal_fn ifn; + + switch (fcode) + { + case BUILT_IN_ADDC: + case BUILT_IN_ADDCL: + case BUILT_IN_ADDCLL: + ifn = IFN_ADD_OVERFLOW; + break; + case BUILT_IN_SUBC: + case BUILT_IN_SUBCL: + case BUILT_IN_SUBCLL: + ifn = IFN_SUB_OVERFLOW; + break; + default: + gcc_unreachable (); + } + + tree type = TREE_TYPE (args[0]); + tree ctype = build_complex_type (type); + tree call = build_call_expr_internal_loc (loc, ifn, ctype, 2, + args[0], args[1]); + tree tgt = save_expr (call); + tree intres = build1_loc (loc, REALPART_EXPR, type, tgt); + tree ovfres = build1_loc (loc, IMAGPART_EXPR, type, tgt); + call = build_call_expr_internal_loc (loc, ifn, ctype, 2, + intres, args[2]); + tgt = save_expr (call); + intres = build1_loc (loc, REALPART_EXPR, type, tgt); + tree ovfres2 = build1_loc (loc, IMAGPART_EXPR, type, tgt); + ovfres = build2_loc (loc, BIT_IOR_EXPR, type, ovfres, ovfres2); + tree mem_arg3 = build_fold_indirect_ref_loc (loc, args[3]); + tree store + = fold_build2_loc (loc, MODIFY_EXPR, void_type_node, mem_arg3, ovfres); + return build2_loc (loc, COMPOUND_EXPR, type, store, intres); +} + /* Fold a call to __builtin_FILE to a constant string. */ static inline tree @@ -10843,6 +10888,14 @@ fold_builtin_varargs (location_t loc, tree fndecl, tree *args, int nargs) ret = fold_builtin_fpclassify (loc, args, nargs); break; + case BUILT_IN_ADDC: + case BUILT_IN_ADDCL: + case BUILT_IN_ADDCLL: + case BUILT_IN_SUBC: + case BUILT_IN_SUBCL: + case BUILT_IN_SUBCLL: + return fold_builtin_addc_subc (loc, fcode, args); + default: break; } |