From patchwork Fri Jun 2 13:32:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 70511 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A92233856DD6 for ; Fri, 2 Jun 2023 13:33:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A92233856DD6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1685712801; bh=brP46QZaYonPKY08OwW4WGjxvfN77Ku9SP1Xl5o3qC0=; h=To:Cc:Subject:Date:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=BsvRYxHUfZtOodiiOfhcS7+SL/bsli9ApyrhkqHiuUJMV6ACDJOxtf8p7T5+4aExC eTg80JG/Xx7oelDJwSEeO0qWlFG9tXWGFIlWXBq3bncpe9pUsLlvqD6LGok1OLGvJd zJivKpz94arSB0hrIOdZ+N26znOHroTW54sUXa9M= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 389B53858D3C for ; Fri, 2 Jun 2023 13:32:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 389B53858D3C Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-37-_SMW3P0BMNaPx75y-dh95A-1; Fri, 02 Jun 2023 09:32:47 -0400 X-MC-Unique: _SMW3P0BMNaPx75y-dh95A-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.rdu2.redhat.com [10.11.54.8]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 40B10185A78E for ; Fri, 2 Jun 2023 13:32:47 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.22.34.14]) by smtp.corp.redhat.com (Postfix) with ESMTP id 077B1C154D7; Fri, 2 Jun 2023 13:32:46 +0000 (UTC) To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [pushed] analyzer: implement various atomic builtins [PR109015] Date: Fri, 2 Jun 2023 09:32:45 -0400 Message-Id: <20230602133245.66990-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.8 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: David Malcolm via Gcc-patches From: David Malcolm Reply-To: David Malcolm Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" 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 ()); + kfm.add (BUILT_IN_ATOMIC_EXCHANGE_N, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_EXCHANGE_1, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_EXCHANGE_2, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_EXCHANGE_4, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_EXCHANGE_8, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_EXCHANGE_16, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_LOAD, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_LOAD_N, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_LOAD_1, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_LOAD_2, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_LOAD_4, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_LOAD_8, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_LOAD_16, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_STORE_N, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_STORE_1, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_STORE_2, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_STORE_4, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_STORE_8, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_STORE_16, make_unique ()); + kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_1, + make_unique (PLUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_2, + make_unique (PLUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_4, + make_unique (PLUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_8, + make_unique (PLUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_16, + make_unique (PLUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_1, + make_unique (MINUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_2, + make_unique (MINUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_4, + make_unique (MINUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_8, + make_unique (MINUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_16, + make_unique (MINUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_AND_FETCH_1, + make_unique (BIT_AND_EXPR)); + kfm.add (BUILT_IN_ATOMIC_AND_FETCH_2, + make_unique (BIT_AND_EXPR)); + kfm.add (BUILT_IN_ATOMIC_AND_FETCH_4, + make_unique (BIT_AND_EXPR)); + kfm.add (BUILT_IN_ATOMIC_AND_FETCH_8, + make_unique (BIT_AND_EXPR)); + kfm.add (BUILT_IN_ATOMIC_AND_FETCH_16, + make_unique (BIT_AND_EXPR)); + kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_1, + make_unique (BIT_XOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_2, + make_unique (BIT_XOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_4, + make_unique (BIT_XOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_8, + make_unique (BIT_XOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_16, + make_unique (BIT_XOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_OR_FETCH_1, + make_unique (BIT_IOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_OR_FETCH_2, + make_unique (BIT_IOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_OR_FETCH_4, + make_unique (BIT_IOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_OR_FETCH_8, + make_unique (BIT_IOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_OR_FETCH_16, + make_unique (BIT_IOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_1, + make_unique (PLUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_2, + make_unique (PLUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_4, + make_unique (PLUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_8, + make_unique (PLUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_16, + make_unique (PLUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_1, + make_unique (MINUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_2, + make_unique (MINUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_4, + make_unique (MINUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_8, + make_unique (MINUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_16, + make_unique (MINUS_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_AND_1, + make_unique (BIT_AND_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_AND_2, + make_unique (BIT_AND_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_AND_4, + make_unique (BIT_AND_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_AND_8, + make_unique (BIT_AND_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_AND_16, + make_unique (BIT_AND_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_1, + make_unique (BIT_XOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_2, + make_unique (BIT_XOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_4, + make_unique (BIT_XOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_8, + make_unique (BIT_XOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_16, + make_unique (BIT_XOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_OR_1, + make_unique (BIT_IOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_OR_2, + make_unique (BIT_IOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_OR_4, + make_unique (BIT_IOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_OR_8, + make_unique (BIT_IOR_EXPR)); + kfm.add (BUILT_IN_ATOMIC_FETCH_OR_16, + make_unique (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 ()); kfm.add (BUILT_IN_STRLEN, make_unique ()); + 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 + +#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" } */ +}