diff mbox series

[pushed] analyzer: implement various atomic builtins [PR109015]

Message ID 20230602133245.66990-1-dmalcolm@redhat.com
State New
Headers show
Series [pushed] analyzer: implement various atomic builtins [PR109015] | expand

Commit Message

David Malcolm June 2, 2023, 1:32 p.m. UTC
This patch implements many of the __atomic_* builtins from
sync-builtins.def as known_function subclasses within the analyzer.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to trunk as r14-1497-gef768035ae8090.

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.
---
 gcc/analyzer/kf.cc                            | 355 ++++++++++++
 .../gcc.dg/analyzer/atomic-builtins-1.c       | 544 ++++++++++++++++++
 .../analyzer/atomic-builtins-haproxy-proxy.c  |  55 ++
 .../analyzer/atomic-builtins-qemu-sockets.c   |  18 +
 .../gcc.dg/analyzer/atomic-types-1.c          |  11 +
 5 files changed, 983 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/atomic-builtins-1.c
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/atomic-builtins-haproxy-proxy.c
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/atomic-builtins-qemu-sockets.c
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/atomic-types-1.c

Comments

Maxim Kuvyrkov June 3, 2023, 5:23 a.m. UTC | #1
Hi David,

The new test ICEs the compiler on aarch64-linux-gnu [1].  Would you please investigate?

Running gcc:gcc.dg/analyzer/analyzer.exp ...
FAIL: gcc.dg/analyzer/atomic-builtins-qemu-sockets.c (internal compiler error: in validate, at analyzer/store.cc:1329)
FAIL: gcc.dg/analyzer/atomic-builtins-qemu-sockets.c (test for excess errors)

This is a simple native build on aarch64-linux-gnu.  Please let me know if you need any help in reproducing this.

[1] https://ci.linaro.org/job/tcwg_gcc_check--master-aarch64-build/82/artifact/artifacts/artifacts.precommit/06-check_regression/results.compare/*view*/

Thanks!

--
Maxim Kuvyrkov
https://www.linaro.org




> On Jun 2, 2023, at 17:32, David Malcolm via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> 
> This patch implements many of the __atomic_* builtins from
> sync-builtins.def as known_function subclasses within the analyzer.
> 
> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
> Pushed to trunk as r14-1497-gef768035ae8090.
> 
> 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.
> ---
> gcc/analyzer/kf.cc                            | 355 ++++++++++++
> .../gcc.dg/analyzer/atomic-builtins-1.c       | 544 ++++++++++++++++++
> .../analyzer/atomic-builtins-haproxy-proxy.c  |  55 ++
> .../analyzer/atomic-builtins-qemu-sockets.c   |  18 +
> .../gcc.dg/analyzer/atomic-types-1.c          |  11 +
> 5 files changed, 983 insertions(+)
> create mode 100644 gcc/testsuite/gcc.dg/analyzer/atomic-builtins-1.c
> create mode 100644 gcc/testsuite/gcc.dg/analyzer/atomic-builtins-haproxy-proxy.c
> create mode 100644 gcc/testsuite/gcc.dg/analyzer/atomic-builtins-qemu-sockets.c
> create mode 100644 gcc/testsuite/gcc.dg/analyzer/atomic-types-1.c
> 
> 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" } */  
> +}
> -- 
> 2.26.3
>
Maxim Kuvyrkov June 5, 2023, 11:38 a.m. UTC | #2
Hi David,

Hm, I'm seeing this failure only in pre-commit testing, but I don't see it in our post-commit testing of gcc:master.

Does this patch rely on your other patch committed just before this one?

--
Maxim Kuvyrkov
https://www.linaro.org




> On Jun 3, 2023, at 09:23, Maxim Kuvyrkov <maxim.kuvyrkov@linaro.org> wrote:
> 
> Hi David,
> 
> The new test ICEs the compiler on aarch64-linux-gnu [1].  Would you please investigate?
> 
> Running gcc:gcc.dg/analyzer/analyzer.exp ...
> FAIL: gcc.dg/analyzer/atomic-builtins-qemu-sockets.c (internal compiler error: in validate, at analyzer/store.cc:1329)
> FAIL: gcc.dg/analyzer/atomic-builtins-qemu-sockets.c (test for excess errors)
> 
> This is a simple native build on aarch64-linux-gnu.  Please let me know if you need any help in reproducing this.
> 
> [1] https://ci.linaro.org/job/tcwg_gcc_check--master-aarch64-build/82/artifact/artifacts/artifacts.precommit/06-check_regression/results.compare/*view*/
> 
> Thanks!
> 
> --
> Maxim Kuvyrkov
> https://www.linaro.org
> 
> 
> 
> 
>> On Jun 2, 2023, at 17:32, David Malcolm via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>> 
>> This patch implements many of the __atomic_* builtins from
>> sync-builtins.def as known_function subclasses within the analyzer.
>> 
>> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
>> Pushed to trunk as r14-1497-gef768035ae8090.
>> 
>> 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.
>> ---
>> gcc/analyzer/kf.cc                            | 355 ++++++++++++
>> .../gcc.dg/analyzer/atomic-builtins-1.c       | 544 ++++++++++++++++++
>> .../analyzer/atomic-builtins-haproxy-proxy.c  |  55 ++
>> .../analyzer/atomic-builtins-qemu-sockets.c   |  18 +
>> .../gcc.dg/analyzer/atomic-types-1.c          |  11 +
>> 5 files changed, 983 insertions(+)
>> create mode 100644 gcc/testsuite/gcc.dg/analyzer/atomic-builtins-1.c
>> create mode 100644 gcc/testsuite/gcc.dg/analyzer/atomic-builtins-haproxy-proxy.c
>> create mode 100644 gcc/testsuite/gcc.dg/analyzer/atomic-builtins-qemu-sockets.c
>> create mode 100644 gcc/testsuite/gcc.dg/analyzer/atomic-types-1.c
>> 
>> 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" } */  
>> +}
>> -- 
>> 2.26.3
>> 
>
diff mbox series

Patch

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" } */  
+}