aboutsummaryrefslogtreecommitdiff
path: root/gcc/builtins.cc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2023-06-16 19:47:28 +0200
committerJakub Jelinek <jakub@redhat.com>2023-06-16 19:47:28 +0200
commit2b4e0415ad664cdb3ce87d1f7eee5ca26911a05b (patch)
tree899721fe206660eca7d72307acf6107606613c05 /gcc/builtins.cc
parent5b67116a85298bbe358b036d34ad23119cebbdac (diff)
downloadgcc-upstream-2b4e0415ad664cdb3ce87d1f7eee5ca26911a05b.tar.gz
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.cc53
1 files changed, 53 insertions, 0 deletions
diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index 8400adaf5b4..6dff5214ff8 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;
}