public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-1497] analyzer: implement various atomic builtins [PR109015]
@ 2023-06-02 13:29 David Malcolm
0 siblings, 0 replies; only message in thread
From: David Malcolm @ 2023-06-02 13:29 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:ef768035ae8090ecbe5726111a5fae4d5c86dd74
commit r14-1497-gef768035ae8090ecbe5726111a5fae4d5c86dd74
Author: David Malcolm <dmalcolm@redhat.com>
Date: Fri Jun 2 09:28:30 2023 -0400
analyzer: implement various atomic builtins [PR109015]
This patch implements many of the __atomic_* builtins from
sync-builtins.def as known_function subclasses within the analyzer.
gcc/analyzer/ChangeLog:
PR analyzer/109015
* kf.cc (class kf_atomic_exchange): New.
(class kf_atomic_exchange_n): New.
(class kf_atomic_fetch_op): New.
(class kf_atomic_op_fetch): New.
(class kf_atomic_load): New.
(class kf_atomic_load_n): New.
(class kf_atomic_store_n): New.
(register_atomic_builtins): New function.
(register_known_functions): Call register_atomic_builtins.
gcc/testsuite/ChangeLog:
PR analyzer/109015
* gcc.dg/analyzer/atomic-builtins-1.c: New test.
* gcc.dg/analyzer/atomic-builtins-haproxy-proxy.c: New test.
* gcc.dg/analyzer/atomic-builtins-qemu-sockets.c: New test.
* gcc.dg/analyzer/atomic-types-1.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diff:
---
gcc/analyzer/kf.cc | 355 ++++++++++++++
gcc/testsuite/gcc.dg/analyzer/atomic-builtins-1.c | 544 +++++++++++++++++++++
.../analyzer/atomic-builtins-haproxy-proxy.c | 55 +++
.../gcc.dg/analyzer/atomic-builtins-qemu-sockets.c | 18 +
gcc/testsuite/gcc.dg/analyzer/atomic-types-1.c | 11 +
5 files changed, 983 insertions(+)
diff --git a/gcc/analyzer/kf.cc b/gcc/analyzer/kf.cc
index 93c46630f36..1044111199e 100644
--- a/gcc/analyzer/kf.cc
+++ b/gcc/analyzer/kf.cc
@@ -69,6 +69,235 @@ kf_alloca::impl_call_pre (const call_details &cd) const
cd.maybe_set_lhs (ptr_sval);
}
+/* Handler for:
+ void __atomic_exchange (type *ptr, type *val, type *ret, int memorder). */
+
+class kf_atomic_exchange : public internal_known_function
+{
+public:
+ /* This is effectively:
+ *RET = *PTR;
+ *PTR = *VAL;
+ */
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ const svalue *ptr_ptr_sval = cd.get_arg_svalue (0);
+ tree ptr_ptr_tree = cd.get_arg_tree (0);
+ const svalue *val_ptr_sval = cd.get_arg_svalue (1);
+ tree val_ptr_tree = cd.get_arg_tree (1);
+ const svalue *ret_ptr_sval = cd.get_arg_svalue (2);
+ tree ret_ptr_tree = cd.get_arg_tree (2);
+ /* Ignore the memorder param. */
+
+ region_model *model = cd.get_model ();
+ region_model_context *ctxt = cd.get_ctxt ();
+
+ const region *val_region
+ = model->deref_rvalue (val_ptr_sval, val_ptr_tree, ctxt);
+ const svalue *star_val_sval = model->get_store_value (val_region, ctxt);
+ const region *ptr_region
+ = model->deref_rvalue (ptr_ptr_sval, ptr_ptr_tree, ctxt);
+ const svalue *star_ptr_sval = model->get_store_value (ptr_region, ctxt);
+ const region *ret_region
+ = model->deref_rvalue (ret_ptr_sval, ret_ptr_tree, ctxt);
+ model->set_value (ptr_region, star_val_sval, ctxt);
+ model->set_value (ret_region, star_ptr_sval, ctxt);
+ }
+};
+
+/* Handler for:
+ __atomic_exchange_n (type *ptr, type val, int memorder). */
+
+class kf_atomic_exchange_n : public internal_known_function
+{
+public:
+ /* This is effectively:
+ RET = *PTR;
+ *PTR = VAL;
+ return RET;
+ */
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ const svalue *ptr_sval = cd.get_arg_svalue (0);
+ tree ptr_tree = cd.get_arg_tree (0);
+ const svalue *set_sval = cd.get_arg_svalue (1);
+ /* Ignore the memorder param. */
+
+ region_model *model = cd.get_model ();
+ region_model_context *ctxt = cd.get_ctxt ();
+
+ const region *dst_region = model->deref_rvalue (ptr_sval, ptr_tree, ctxt);
+ const svalue *ret_sval = model->get_store_value (dst_region, ctxt);
+ model->set_value (dst_region, set_sval, ctxt);
+ cd.maybe_set_lhs (ret_sval);
+ }
+};
+
+/* Handler for:
+ type __atomic_fetch_add (type *ptr, type val, int memorder);
+ type __atomic_fetch_sub (type *ptr, type val, int memorder);
+ type __atomic_fetch_and (type *ptr, type val, int memorder);
+ type __atomic_fetch_xor (type *ptr, type val, int memorder);
+ type __atomic_fetch_or (type *ptr, type val, int memorder);
+*/
+
+class kf_atomic_fetch_op : public internal_known_function
+{
+public:
+ kf_atomic_fetch_op (enum tree_code op): m_op (op) {}
+
+ /* This is effectively:
+ RET = *PTR;
+ *PTR = RET OP VAL;
+ return RET;
+ */
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ const svalue *ptr_sval = cd.get_arg_svalue (0);
+ tree ptr_tree = cd.get_arg_tree (0);
+ const svalue *val_sval = cd.get_arg_svalue (1);
+ /* Ignore the memorder param. */
+
+ region_model *model = cd.get_model ();
+ region_model_manager *mgr = cd.get_manager ();
+ region_model_context *ctxt = cd.get_ctxt ();
+
+ const region *star_ptr_region
+ = model->deref_rvalue (ptr_sval, ptr_tree, ctxt);
+ const svalue *old_sval = model->get_store_value (star_ptr_region, ctxt);
+ const svalue *new_sval = mgr->get_or_create_binop (old_sval->get_type (),
+ m_op,
+ old_sval, val_sval);
+ model->set_value (star_ptr_region, new_sval, ctxt);
+ cd.maybe_set_lhs (old_sval);
+ }
+
+private:
+ enum tree_code m_op;
+};
+
+/* Handler for:
+ type __atomic_add_fetch (type *ptr, type val, int memorder);
+ type __atomic_sub_fetch (type *ptr, type val, int memorder);
+ type __atomic_and_fetch (type *ptr, type val, int memorder);
+ type __atomic_xor_fetch (type *ptr, type val, int memorder);
+ type __atomic_or_fetch (type *ptr, type val, int memorder);
+*/
+
+class kf_atomic_op_fetch : public internal_known_function
+{
+public:
+ kf_atomic_op_fetch (enum tree_code op): m_op (op) {}
+
+ /* This is effectively:
+ *PTR = RET OP VAL;
+ return *PTR;
+ */
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ const svalue *ptr_sval = cd.get_arg_svalue (0);
+ tree ptr_tree = cd.get_arg_tree (0);
+ const svalue *val_sval = cd.get_arg_svalue (1);
+ /* Ignore the memorder param. */
+
+ region_model *model = cd.get_model ();
+ region_model_manager *mgr = cd.get_manager ();
+ region_model_context *ctxt = cd.get_ctxt ();
+
+ const region *star_ptr_region
+ = model->deref_rvalue (ptr_sval, ptr_tree, ctxt);
+ const svalue *old_sval = model->get_store_value (star_ptr_region, ctxt);
+ const svalue *new_sval = mgr->get_or_create_binop (old_sval->get_type (),
+ m_op,
+ old_sval, val_sval);
+ model->set_value (star_ptr_region, new_sval, ctxt);
+ cd.maybe_set_lhs (new_sval);
+ }
+
+private:
+ enum tree_code m_op;
+};
+
+/* Handler for:
+ void __atomic_load (type *ptr, type *ret, int memorder). */
+
+class kf_atomic_load : public internal_known_function
+{
+public:
+ /* This is effectively:
+ *RET = *PTR;
+ */
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ const svalue *ptr_ptr_sval = cd.get_arg_svalue (0);
+ tree ptr_ptr_tree = cd.get_arg_tree (0);
+ const svalue *ret_ptr_sval = cd.get_arg_svalue (1);
+ tree ret_ptr_tree = cd.get_arg_tree (1);
+ /* Ignore the memorder param. */
+
+ region_model *model = cd.get_model ();
+ region_model_context *ctxt = cd.get_ctxt ();
+
+ const region *ptr_region
+ = model->deref_rvalue (ptr_ptr_sval, ptr_ptr_tree, ctxt);
+ const svalue *star_ptr_sval = model->get_store_value (ptr_region, ctxt);
+ const region *ret_region
+ = model->deref_rvalue (ret_ptr_sval, ret_ptr_tree, ctxt);
+ model->set_value (ret_region, star_ptr_sval, ctxt);
+ }
+};
+
+/* Handler for:
+ type __atomic_load_n (type *ptr, int memorder) */
+
+class kf_atomic_load_n : public internal_known_function
+{
+public:
+ /* This is effectively:
+ RET = *PTR;
+ return RET;
+ */
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ const svalue *ptr_ptr_sval = cd.get_arg_svalue (0);
+ tree ptr_ptr_tree = cd.get_arg_tree (0);
+ /* Ignore the memorder param. */
+
+ region_model *model = cd.get_model ();
+ region_model_context *ctxt = cd.get_ctxt ();
+
+ const region *ptr_region
+ = model->deref_rvalue (ptr_ptr_sval, ptr_ptr_tree, ctxt);
+ const svalue *star_ptr_sval = model->get_store_value (ptr_region, ctxt);
+ cd.maybe_set_lhs (star_ptr_sval);
+ }
+};
+
+/* Handler for:
+ void __atomic_store_n (type *ptr, type val, int memorder) */
+
+class kf_atomic_store_n : public internal_known_function
+{
+public:
+ /* This is effectively:
+ *PTR = VAL;
+ */
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ const svalue *ptr_sval = cd.get_arg_svalue (0);
+ tree ptr_tree = cd.get_arg_tree (0);
+ const svalue *new_sval = cd.get_arg_svalue (1);
+ /* Ignore the memorder param. */
+
+ region_model *model = cd.get_model ();
+ region_model_context *ctxt = cd.get_ctxt ();
+
+ const region *star_ptr_region
+ = model->deref_rvalue (ptr_sval, ptr_tree, ctxt);
+ model->set_value (star_ptr_region, new_sval, ctxt);
+ }
+};
+
/* Handler for "__builtin_expect" etc. */
class kf_expect : public internal_known_function
@@ -987,6 +1216,131 @@ region_model::impl_deallocation_call (const call_details &cd)
kf.impl_call_post (cd);
}
+static void
+register_atomic_builtins (known_function_manager &kfm)
+{
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE, make_unique<kf_atomic_exchange> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_N, make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_1, make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_2, make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_4, make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_8, make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_16, make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD, make_unique<kf_atomic_load> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_N, make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_1, make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_2, make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_4, make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_8, make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_16, make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_N, make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_1, make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_2, make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_4, make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_8, make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_16, make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_1,
+ make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_2,
+ make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_4,
+ make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_8,
+ make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_16,
+ make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_1,
+ make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_2,
+ make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_4,
+ make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_8,
+ make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_16,
+ make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_AND_FETCH_1,
+ make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_AND_FETCH_2,
+ make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_AND_FETCH_4,
+ make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_AND_FETCH_8,
+ make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_AND_FETCH_16,
+ make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_1,
+ make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_2,
+ make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_4,
+ make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_8,
+ make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_16,
+ make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_OR_FETCH_1,
+ make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_OR_FETCH_2,
+ make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_OR_FETCH_4,
+ make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_OR_FETCH_8,
+ make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_OR_FETCH_16,
+ make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_1,
+ make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_2,
+ make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_4,
+ make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_8,
+ make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_16,
+ make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_1,
+ make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_2,
+ make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_4,
+ make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_8,
+ make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_16,
+ make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_AND_1,
+ make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_AND_2,
+ make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_AND_4,
+ make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_AND_8,
+ make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_AND_16,
+ make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_1,
+ make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_2,
+ make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_4,
+ make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_8,
+ make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_16,
+ make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_OR_1,
+ make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_OR_2,
+ make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_OR_4,
+ make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_OR_8,
+ make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
+ kfm.add (BUILT_IN_ATOMIC_FETCH_OR_16,
+ make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
+}
+
/* Populate KFM with instances of known functions supported by the core of the
analyzer (as opposed to plugins). */
@@ -1028,6 +1382,7 @@ register_known_functions (known_function_manager &kfm)
kfm.add (BUILT_IN_STRNDUP, make_unique<kf_strndup> ());
kfm.add (BUILT_IN_STRLEN, make_unique<kf_strlen> ());
+ register_atomic_builtins (kfm);
register_varargs_builtins (kfm);
}
diff --git a/gcc/testsuite/gcc.dg/analyzer/atomic-builtins-1.c b/gcc/testsuite/gcc.dg/analyzer/atomic-builtins-1.c
new file mode 100644
index 00000000000..69eac3f87fd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/atomic-builtins-1.c
@@ -0,0 +1,544 @@
+/* { dg-require-effective-target int128 } */
+/* { dg-require-effective-target sync_char_short } */
+/* { dg-require-effective-target sync_int_long_stack } */
+/* { dg-require-effective-target sync_int_long } */
+
+#include <stdint.h>
+
+#include "analyzer-decls.h"
+
+/* __atomic_exchange. */
+
+void test__atomic_exchange_on_int8 (int8_t i, int8_t j)
+{
+ int8_t orig_i = i;
+ int8_t orig_j = j;
+ int8_t ret;
+ __atomic_exchange (&i, &j, &ret, 0);
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (i == orig_j); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_exchange_on_int16 (int16_t i, int16_t j)
+{
+ int16_t orig_i = i;
+ int16_t orig_j = j;
+ int16_t ret;
+ __atomic_exchange (&i, &j, &ret, 0);
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (i == orig_j); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_exchange_on_int32 (int32_t i, int32_t j)
+{
+ int32_t orig_i = i;
+ int32_t orig_j = j;
+ int32_t ret;
+ __atomic_exchange (&i, &j, &ret, 0);
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (i == orig_j); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_exchange_on_int64 (int64_t i, int64_t j)
+{
+ int64_t orig_i = i;
+ int64_t orig_j = j;
+ int64_t ret;
+ __atomic_exchange (&i, &j, &ret, 0);
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (i == orig_j); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_exchange_on_int128 (__int128 i, __int128 j)
+{
+ __int128 orig_i = i;
+ __int128 orig_j = j;
+ __int128 ret;
+ __atomic_exchange (&i, &j, &ret, 0);
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (i == orig_j); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_exchange_n. */
+
+void test__atomic_exchange_n_on_int8 (int8_t i, int8_t j)
+{
+ int8_t orig_i = i;
+ int8_t orig_j = j;
+ int8_t ret;
+ ret = __atomic_exchange_n (&i, j, 0);
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (i == orig_j); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_exchange_n_on_int16 (int16_t i, int16_t j)
+{
+ int16_t orig_i = i;
+ int16_t orig_j = j;
+ int16_t ret;
+ ret = __atomic_exchange_n (&i, j, 0);
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (i == orig_j); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_exchange_n_on_int32 (int32_t i, int32_t j)
+{
+ int32_t orig_i = i;
+ int32_t orig_j = j;
+ int32_t ret;
+ ret = __atomic_exchange_n (&i, j, 0);
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (i == orig_j); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_exchange_n_on_int64 (int64_t i, int64_t j)
+{
+ int64_t orig_i = i;
+ int64_t orig_j = j;
+ int64_t ret;
+ ret = __atomic_exchange_n (&i, j, 0);
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (i == orig_j); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_exchange_n_on_int128 (__int128 i, __int128 j)
+{
+ __int128 orig_i = i;
+ __int128 orig_j = j;
+ __int128 ret;
+ ret = __atomic_exchange_n (&i, j, 0);
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (i == orig_j); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_exchange_1 through __atomic_exchange_16. */
+
+void test__atomic_exchange_1 (int8_t i, int8_t j)
+{
+ int8_t orig_i = i;
+ int8_t orig_j = j;
+ int8_t ret;
+ ret = __atomic_exchange_1 (&i, j, 0);
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (i == orig_j); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_exchange_2 (int16_t i, int16_t j)
+{
+ int16_t orig_i = i;
+ int16_t orig_j = j;
+ int16_t ret;
+ ret = __atomic_exchange_2 (&i, j, 0);
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (i == orig_j); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_exchange_4 (int32_t i, int32_t j)
+{
+ int32_t orig_i = i;
+ int32_t orig_j = j;
+ int32_t ret;
+ ret = __atomic_exchange_4 (&i, j, 0);
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (i == orig_j); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_exchange_8 (int64_t i, int64_t j)
+{
+ int64_t orig_i = i;
+ int64_t orig_j = j;
+ int64_t ret;
+ ret = __atomic_exchange_8 (&i, j, 0);
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (i == orig_j); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_exchange_16 (__int128 i, __int128 j)
+{
+ __int128 orig_i = i;
+ __int128 orig_j = j;
+ __int128 ret;
+ ret = __atomic_exchange_16 (&i, j, 0);
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (i == orig_j); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_load. */
+
+void test__atomic_load_from_int8 (int8_t i)
+{
+ int8_t orig_i = i;
+ int8_t ret;
+ __atomic_load (&i, &ret, 0);
+ __analyzer_eval (i == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_load_from_int16 (int16_t i)
+{
+ int16_t orig_i = i;
+ int16_t ret;
+ __atomic_load (&i, &ret, 0);
+ __analyzer_eval (i == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_load_from_int32 (int32_t i)
+{
+ int32_t orig_i = i;
+ int32_t ret;
+ __atomic_load (&i, &ret, 0);
+ __analyzer_eval (i == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_load_from_int64 (int64_t i)
+{
+ int64_t orig_i = i;
+ int64_t ret;
+ __atomic_load (&i, &ret, 0);
+ __analyzer_eval (i == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_load_from_int1288 (__int128 i)
+{
+ __int128 orig_i = i;
+ __int128 ret;
+ __atomic_load (&i, &ret, 0);
+ __analyzer_eval (i == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_load_n. */
+
+void test__atomic_load_n_from_int8 (int8_t i)
+{
+ int8_t orig_i = i;
+ int8_t ret;
+ ret = __atomic_load_n (&i, 0);
+ __analyzer_eval (i == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_load_n_from_int16 (int16_t i)
+{
+ int16_t orig_i = i;
+ int16_t ret;
+ ret = __atomic_load_n (&i, 0);
+ __analyzer_eval (i == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_load_n_from_int32 (int32_t i)
+{
+ int32_t orig_i = i;
+ int32_t ret;
+ ret = __atomic_load_n (&i, 0);
+ __analyzer_eval (i == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_load_n_from_int64 (int64_t i)
+{
+ int64_t orig_i = i;
+ int64_t ret;
+ ret = __atomic_load_n (&i, 0);
+ __analyzer_eval (i == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_load_n_from_int128 (__int128 i)
+{
+ __int128 orig_i = i;
+ __int128 ret;
+ ret = __atomic_load_n (&i, 0);
+ __analyzer_eval (i == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_load_1 through __atomic_load_16. */
+
+void test__atomic_load_1 (int8_t i)
+{
+ int8_t orig_i = i;
+ int8_t ret;
+ ret = __atomic_load_1 (&i, 0);
+ __analyzer_eval (i == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_load_2 (int16_t i)
+{
+ int16_t orig_i = i;
+ int16_t ret;
+ ret = __atomic_load_2 (&i, 0);
+ __analyzer_eval (i == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_load_4 (int32_t i)
+{
+ int32_t orig_i = i;
+ int32_t ret;
+ ret = __atomic_load_4 (&i, 0);
+ __analyzer_eval (i == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_load_8 (int64_t i)
+{
+ int64_t orig_i = i;
+ int64_t ret;
+ ret = __atomic_load_8 (&i, 0);
+ __analyzer_eval (i == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_load_16 (__int128 i)
+{
+ __int128 orig_i = i;
+ __int128 ret;
+ ret = __atomic_load_16 (&i, 0);
+ __analyzer_eval (i == orig_i); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_store_n_on_uint8 (uint8_t i)
+{
+ uint8_t tmp;
+ __atomic_store_n (&tmp, i, 0);
+ __analyzer_eval (tmp == i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_store_n_on_uint16 (uint16_t i)
+{
+ uint16_t tmp;
+ __atomic_store_n (&tmp, i, 0);
+ __analyzer_eval (tmp == i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_store_n_on_uint32 (uint32_t i)
+{
+ uint32_t tmp;
+ __atomic_store_n (&tmp, i, 0);
+ __analyzer_eval (tmp == i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_store_n_on_uint64 (uint64_t i)
+{
+ uint64_t tmp;
+ __atomic_store_n (&tmp, i, 0);
+ __analyzer_eval (tmp == i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_store_n_on_int128 (__int128 i)
+{
+ __int128 tmp;
+ __atomic_store_n (&tmp, i, 0);
+ __analyzer_eval (tmp == i); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_OP_fetch built-ins. */
+
+/* __atomic_add_fetch. */
+
+void test__atomic_add_fetch_on_uint32_t (uint32_t i, uint32_t j)
+{
+ uint32_t orig_i = i;
+ uint32_t ret;
+ ret = __atomic_add_fetch (&i, j, 0);
+ __analyzer_eval (i == (orig_i + j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_add_fetch_on_uint64_t (uint64_t i, uint64_t j)
+{
+ uint64_t orig_i = i;
+ uint64_t ret;
+ ret = __atomic_add_fetch (&i, j, 0);
+ __analyzer_eval (i == (orig_i + j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_sub_fetch. */
+
+void test__atomic_sub_fetch_on_uint32_t (uint32_t i, uint32_t j)
+{
+ uint32_t orig_i = i;
+ uint32_t ret;
+ ret = __atomic_sub_fetch (&i, j, 0);
+ __analyzer_eval (i == (orig_i - j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_sub_fetch_on_uint64_t (uint64_t i, uint64_t j)
+{
+ uint64_t orig_i = i;
+ uint64_t ret;
+ ret = __atomic_sub_fetch (&i, j, 0);
+ __analyzer_eval (i == (orig_i - j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_and_fetch. */
+
+void test__atomic_and_fetch_on_uint32_t (uint32_t i, uint32_t j)
+{
+ uint32_t orig_i = i;
+ uint32_t ret;
+ ret = __atomic_and_fetch (&i, j, 0);
+ __analyzer_eval (i == (orig_i & j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_and_fetch_on_uint64_t (uint64_t i, uint64_t j)
+{
+ uint64_t orig_i = i;
+ uint64_t ret;
+ ret = __atomic_and_fetch (&i, j, 0);
+ __analyzer_eval (i == (orig_i & j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_xor_fetch. */
+
+void test__atomic_xor_fetch_on_uint32_t (uint32_t i, uint32_t j)
+{
+ uint32_t orig_i = i;
+ uint32_t ret;
+ ret = __atomic_xor_fetch (&i, j, 0);
+ __analyzer_eval (i == (orig_i ^ j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_xor_fetch_on_uint64_t (uint64_t i, uint64_t j)
+{
+ uint64_t orig_i = i;
+ uint64_t ret;
+ ret = __atomic_xor_fetch (&i, j, 0);
+ __analyzer_eval (i == (orig_i ^ j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_or_fetch. */
+
+void test__atomic_or_fetch_on_uint32_t (uint32_t i, uint32_t j)
+{
+ uint32_t orig_i = i;
+ uint32_t ret;
+ ret = __atomic_or_fetch (&i, j, 0);
+ __analyzer_eval (i == (orig_i | j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_or_fetch_on_uint64_t (uint64_t i, uint64_t j)
+{
+ uint64_t orig_i = i;
+ uint64_t ret;
+ ret = __atomic_or_fetch (&i, j, 0);
+ __analyzer_eval (i == (orig_i | j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_fetch_OP built-ins. */
+
+/* __atomic_fetch_add. */
+
+void test__atomic_fetch_add_on_uint32_t (uint32_t i, uint32_t j)
+{
+ uint32_t orig_i = i;
+ uint32_t ret;
+ ret = __atomic_fetch_add (&i, j, 0);
+ __analyzer_eval (i == (orig_i + j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_fetch_add_on_uint64_t (uint64_t i, uint64_t j)
+{
+ uint64_t orig_i = i;
+ uint64_t ret;
+ ret = __atomic_fetch_add (&i, j, 0);
+ __analyzer_eval (i == (orig_i + j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_fetch_sub. */
+
+void test__atomic_fetch_sub_on_uint32_t (uint32_t i, uint32_t j)
+{
+ uint32_t orig_i = i;
+ uint32_t ret;
+ ret = __atomic_fetch_sub (&i, j, 0);
+ __analyzer_eval (i == (orig_i - j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_fetch_sub_on_uint64_t (uint64_t i, uint64_t j)
+{
+ uint64_t orig_i = i;
+ uint64_t ret;
+ ret = __atomic_fetch_sub (&i, j, 0);
+ __analyzer_eval (i == (orig_i - j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_fetch_and. */
+
+void test__atomic_fetch_and_on_uint32_t (uint32_t i, uint32_t j)
+{
+ uint32_t orig_i = i;
+ uint32_t ret;
+ ret = __atomic_fetch_and (&i, j, 0);
+ __analyzer_eval (i == (orig_i & j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_fetch_and_on_uint64_t (uint64_t i, uint64_t j)
+{
+ uint64_t orig_i = i;
+ uint64_t ret;
+ ret = __atomic_fetch_and (&i, j, 0);
+ __analyzer_eval (i == (orig_i & j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_fetch_xor. */
+
+void test__atomic_fetch_xor_on_uint32_t (uint32_t i, uint32_t j)
+{
+ uint32_t orig_i = i;
+ uint32_t ret;
+ ret = __atomic_fetch_xor (&i, j, 0);
+ __analyzer_eval (i == (orig_i ^ j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_fetch_xor_on_uint64_t (uint64_t i, uint64_t j)
+{
+ uint64_t orig_i = i;
+ uint64_t ret;
+ ret = __atomic_fetch_xor (&i, j, 0);
+ __analyzer_eval (i == (orig_i ^ j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_fetch_or. */
+
+void test__atomic_fetch_or_on_uint32_t (uint32_t i, uint32_t j)
+{
+ uint32_t orig_i = i;
+ uint32_t ret;
+ ret = __atomic_fetch_or (&i, j, 0);
+ __analyzer_eval (i == (orig_i | j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_fetch_or_on_uint64_t (uint64_t i, uint64_t j)
+{
+ uint64_t orig_i = i;
+ uint64_t ret;
+ ret = __atomic_fetch_or (&i, j, 0);
+ __analyzer_eval (i == (orig_i | j)); /* { dg-warning "TRUE" } */
+ __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/atomic-builtins-haproxy-proxy.c b/gcc/testsuite/gcc.dg/analyzer/atomic-builtins-haproxy-proxy.c
new file mode 100644
index 00000000000..72953a561b8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/atomic-builtins-haproxy-proxy.c
@@ -0,0 +1,55 @@
+/* Reduced from haproxy-2.7.1's proxy.c */
+
+/* { dg-require-effective-target sync_int_long_stack } */
+/* { dg-require-effective-target sync_int_long } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void* malloc(size_t __size)
+ __attribute__((__nothrow__, __leaf__, __malloc__, __alloc_size__(1)));
+
+extern void free(void* __ptr) __attribute__((__nothrow__, __leaf__));
+
+struct error_snapshot
+{
+ /* [..snip...] */
+};
+
+struct proxy
+{
+ /* [..snip...] */
+ struct error_snapshot *invalid_req, *invalid_rep;
+ /* [..snip...] */
+};
+
+extern unsigned int error_snapshot_id;
+
+void
+proxy_capture_error(struct proxy* proxy,
+ int is_back)
+{
+ struct error_snapshot* es;
+ unsigned int ev_id;
+
+ /* [...snip...] */
+
+ ev_id = __atomic_fetch_add(&error_snapshot_id, 1, 5);
+
+ /* [...snip...] */
+
+ es = malloc(sizeof(*es));
+ if (!es)
+ return;
+
+ /* [...snip...] */
+
+ if (is_back) {
+ es = __atomic_exchange_n(&proxy->invalid_rep, es, 4); /* { dg-bogus "leak" } */
+ } else {
+ es = __atomic_exchange_n(&proxy->invalid_req, es, 4); /* { dg-bogus "leak" } */
+ }
+
+ /* [...snip...] */
+
+ free(es);
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/atomic-builtins-qemu-sockets.c b/gcc/testsuite/gcc.dg/analyzer/atomic-builtins-qemu-sockets.c
new file mode 100644
index 00000000000..cd90f8f263d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/atomic-builtins-qemu-sockets.c
@@ -0,0 +1,18 @@
+struct foo {
+ char placeholder[5];
+};
+
+void *
+test (const char *str)
+{
+ struct foo *p = __builtin_malloc(sizeof(struct foo));
+ if (!p)
+ return p;
+
+ __builtin_memset(p, 0, sizeof(*p));
+
+ static int s = 1;
+ __atomic_store_n(&s, 0, 0);
+
+ return p;
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/atomic-types-1.c b/gcc/testsuite/gcc.dg/analyzer/atomic-types-1.c
new file mode 100644
index 00000000000..536b649feea
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/atomic-types-1.c
@@ -0,0 +1,11 @@
+#include "analyzer-decls.h"
+
+_Atomic int i;
+
+void test_atomic_int_1(int x)
+{
+ i = x;
+ __analyzer_eval(i == x); /* { dg-warning "TRUE" } */
+ i++;
+ __analyzer_eval(i == x + 1); /* { dg-warning "TRUE" } */
+}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2023-06-02 13:29 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-02 13:29 [gcc r14-1497] analyzer: implement various atomic builtins [PR109015] David Malcolm
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).