From: Christophe Lyon <christophe.lyon@linaro.org>
To: David Malcolm <dmalcolm@redhat.com>
Cc: gcc Patches <gcc-patches@gcc.gnu.org>
Subject: Re: [committed] analyzer: bitfield fixes [PR99212]
Date: Wed, 9 Jun 2021 16:17:59 +0200 [thread overview]
Message-ID: <CAKdteOZ=fLDT8Sje7Kqgnoc0u3AfzS9daZxCr50Xixsa1TjFxQ@mail.gmail.com> (raw)
In-Reply-To: <20210608185536.1047933-1-dmalcolm@redhat.com>
On Tue, 8 Jun 2021 at 21:34, David Malcolm via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> This patch verifies the previous fix for bitfield sizes by implementing
> enough support for bitfields in the analyzer to get the test cases to pass.
>
> The patch implements support in the analyzer for reading from a
> BIT_FIELD_REF, and support for folding BIT_AND_EXPR of a mask, to handle
> the cases generated in tests.
>
> The existing bitfields tests in data-model-1.c turned out to rely on
> undefined behavior, in that they were assigning values to a signed
> bitfield that were outside of the valid range of values. I believe that
> that's why we were seeing target-specific differences in the test
> results (PR analyzer/99212). The patch updates the test to remove the
> undefined behaviors.
>
> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
> Lightly tested with cris-elf.
>
> Pushed to trunk as r12-1303-gd3b1ef7a83c0c0cd5b20a1dd1714b868f3d2b442.
>
> gcc/analyzer/ChangeLog:
> PR analyzer/99212
> * region-model-manager.cc
> (region_model_manager::maybe_fold_binop): Add support for folding
> BIT_AND_EXPR of compound_svalue and a mask constant.
> * region-model.cc (region_model::get_rvalue_1): Implement
> BIT_FIELD_REF in terms of...
> (region_model::get_rvalue_for_bits): New function.
> * region-model.h (region_model::get_rvalue_for_bits): New decl.
> * store.cc (bit_range::from_mask): New function.
> (selftest::test_bit_range_intersects_p): New selftest.
> (selftest::assert_bit_range_from_mask_eq): New.
> (ASSERT_BIT_RANGE_FROM_MASK_EQ): New macro.
> (selftest::assert_no_bit_range_from_mask_eq): New.
> (ASSERT_NO_BIT_RANGE_FROM_MASK): New macro.
> (selftest::test_bit_range_from_mask): New selftest.
> (selftest::analyzer_store_cc_tests): Call the new selftests.
> * store.h (bit_range::intersects_p): New.
> (bit_range::from_mask): New decl.
> (concrete_binding::get_bit_range): New accessor.
> (store_manager::get_concrete_binding): New overload taking
> const bit_range &.
>
> gcc/testsuite/ChangeLog:
> PR analyzer/99212
> * gcc.dg/analyzer/bitfields-1.c: New test.
> * gcc.dg/analyzer/data-model-1.c (struct sbits): Make bitfields
> explicitly signed.
> (test_44): Update test values assigned to the bits to ones that
> fit in the range of the bitfield type. Remove xfails.
> (test_45): Remove xfails.
>
Hi,
This patch is causing regressions / new failures on armeb (and other
targets according to gcc-testresults):
FAIL: gcc.dg/analyzer/bitfields-1.c (test for excess errors)
Excess errors:
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:24:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:26:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:29:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:31:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:36:3: warning: FALSE
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:41:3: warning: FALSE
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:81:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:83:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:85:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:87:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:92:3: warning: FALSE
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:94:3: warning: FALSE
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:96:3: warning: FALSE
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:113:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:115:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:117:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:119:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:121:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:123:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:125:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c:127:3: warning: UNKNOWN
FAIL: gcc.dg/analyzer/data-model-1.c (test for excess errors)
Excess errors:
/gcc/testsuite/gcc.dg/analyzer/data-model-1.c:947:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/data-model-1.c:950:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/data-model-1.c:965:3: warning: UNKNOWN
/gcc/testsuite/gcc.dg/analyzer/data-model-1.c:968:3: warning: UNKNOWN
For instance with target armeb-none-linux-gnueabihf
Can you check?
Thanks,
Christophe
> Signed-off-by: David Malcolm <dmalcolm@redhat.com>
> ---
> gcc/analyzer/region-model-manager.cc | 46 ++++-
> gcc/analyzer/region-model.cc | 65 ++++++-
> gcc/analyzer/region-model.h | 4 +
> gcc/analyzer/store.cc | 186 +++++++++++++++++++
> gcc/analyzer/store.h | 18 ++
> gcc/testsuite/gcc.dg/analyzer/bitfields-1.c | 144 ++++++++++++++
> gcc/testsuite/gcc.dg/analyzer/data-model-1.c | 30 +--
> 7 files changed, 469 insertions(+), 24 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/analyzer/bitfields-1.c
>
> diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc
> index dfd2413e914..0ca0c8ad02e 100644
> --- a/gcc/analyzer/region-model-manager.cc
> +++ b/gcc/analyzer/region-model-manager.cc
> @@ -480,9 +480,49 @@ region_model_manager::maybe_fold_binop (tree type, enum tree_code op,
> break;
> case BIT_AND_EXPR:
> if (cst1)
> - if (zerop (cst1) && INTEGRAL_TYPE_P (type))
> - /* "(ARG0 & 0)" -> "0". */
> - return get_or_create_constant_svalue (build_int_cst (type, 0));
> + {
> + if (zerop (cst1) && INTEGRAL_TYPE_P (type))
> + /* "(ARG0 & 0)" -> "0". */
> + return get_or_create_constant_svalue (build_int_cst (type, 0));
> +
> + /* Support masking out bits from a compound_svalue, as this
> + is generated when accessing bitfields. */
> + if (const compound_svalue *compound_sval
> + = arg0->dyn_cast_compound_svalue ())
> + {
> + const binding_map &map = compound_sval->get_map ();
> + unsigned HOST_WIDE_INT mask = TREE_INT_CST_LOW (cst1);
> + /* If "mask" is a contiguous range of set bits, see if the
> + compound_sval has a value for those bits. */
> + bit_range bits (0, 0);
> + if (bit_range::from_mask (mask, &bits))
> + {
> + const concrete_binding *conc
> + = get_store_manager ()->get_concrete_binding (bits,
> + BK_direct);
> + if (const svalue *sval = map.get (conc))
> + {
> + /* We have a value;
> + shift it by the correct number of bits. */
> + const svalue *lhs = get_or_create_cast (type, sval);
> + HOST_WIDE_INT bit_offset
> + = bits.get_start_bit_offset ().to_shwi ();
> + tree shift_amt = build_int_cst (type, bit_offset);
> + const svalue *shift_sval
> + = get_or_create_constant_svalue (shift_amt);
> + const svalue *shifted_sval
> + = get_or_create_binop (type,
> + LSHIFT_EXPR,
> + lhs, shift_sval);
> + /* Reapply the mask (needed for negative
> + signed bitfields). */
> + return get_or_create_binop (type,
> + BIT_AND_EXPR,
> + shifted_sval, arg1);
> + }
> + }
> + }
> + }
> break;
> case TRUTH_ANDIF_EXPR:
> case TRUTH_AND_EXPR:
> diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
> index c7038dd2d4b..0d363fb15d3 100644
> --- a/gcc/analyzer/region-model.cc
> +++ b/gcc/analyzer/region-model.cc
> @@ -1357,7 +1357,18 @@ region_model::get_rvalue_1 (path_var pv, region_model_context *ctxt)
> break;
>
> case BIT_FIELD_REF:
> - return m_mgr->get_or_create_unknown_svalue (TREE_TYPE (pv.m_tree));
> + {
> + tree expr = pv.m_tree;
> + tree op0 = TREE_OPERAND (expr, 0);
> + const region *reg = get_lvalue (op0, ctxt);
> + tree num_bits = TREE_OPERAND (expr, 1);
> + tree first_bit_offset = TREE_OPERAND (expr, 2);
> + gcc_assert (TREE_CODE (num_bits) == INTEGER_CST);
> + gcc_assert (TREE_CODE (first_bit_offset) == INTEGER_CST);
> + bit_range bits (TREE_INT_CST_LOW (first_bit_offset),
> + TREE_INT_CST_LOW (num_bits));
> + return get_rvalue_for_bits (TREE_TYPE (expr), reg, bits);
> + }
>
> case SSA_NAME:
> case VAR_DECL:
> @@ -1686,6 +1697,58 @@ region_model::deref_rvalue (const svalue *ptr_sval, tree ptr_tree,
> return m_mgr->get_symbolic_region (ptr_sval);
> }
>
> +/* Attempt to get BITS within any value of REG, as TYPE.
> + In particular, extract values from compound_svalues for the case
> + where there's a concrete binding at BITS.
> + Return an unknown svalue if we can't handle the given case. */
> +
> +const svalue *
> +region_model::get_rvalue_for_bits (tree type,
> + const region *reg,
> + const bit_range &bits)
> +{
> + const svalue *sval = get_store_value (reg);
> + if (const compound_svalue *compound_sval = sval->dyn_cast_compound_svalue ())
> + {
> + const binding_map &map = compound_sval->get_map ();
> + binding_map result_map;
> + for (auto iter : map)
> + {
> + const binding_key *key = iter.first;
> + if (const concrete_binding *conc_key
> + = key->dyn_cast_concrete_binding ())
> + {
> + /* Ignore concrete bindings outside BITS. */
> + if (!conc_key->get_bit_range ().intersects_p (bits))
> + continue;
> + if ((conc_key->get_start_bit_offset ()
> + < bits.get_start_bit_offset ())
> + || (conc_key->get_next_bit_offset ()
> + > bits.get_next_bit_offset ()))
> + {
> + /* If we have any concrete keys that aren't fully within BITS,
> + then bail out. */
> + return m_mgr->get_or_create_unknown_svalue (type);
> + }
> + const concrete_binding *offset_conc_key
> + = m_mgr->get_store_manager ()->get_concrete_binding
> + (conc_key->get_start_bit_offset ()
> + - bits.get_start_bit_offset (),
> + conc_key->get_size_in_bits (),
> + conc_key->get_kind ());
> + const svalue *sval = iter.second;
> + result_map.put (offset_conc_key, sval);
> + }
> + else
> + /* If we have any symbolic keys we can't get it as bits. */
> + return m_mgr->get_or_create_unknown_svalue (type);
> + }
> + return m_mgr->get_or_create_compound_svalue (type, result_map);
> + }
> +
> + return m_mgr->get_or_create_unknown_svalue (type);
> +}
> +
> /* A subclass of pending_diagnostic for complaining about writes to
> constant regions of memory. */
>
> diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
> index a169396dcb5..5e43e547199 100644
> --- a/gcc/analyzer/region-model.h
> +++ b/gcc/analyzer/region-model.h
> @@ -509,6 +509,10 @@ class region_model
> const region *deref_rvalue (const svalue *ptr_sval, tree ptr_tree,
> region_model_context *ctxt);
>
> + const svalue *get_rvalue_for_bits (tree type,
> + const region *reg,
> + const bit_range &bits);
> +
> void set_value (const region *lhs_reg, const svalue *rhs_sval,
> region_model_context *ctxt);
> void set_value (tree lhs, tree rhs, region_model_context *ctxt);
> diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
> index f4bb7def781..699de94cdb0 100644
> --- a/gcc/analyzer/store.cc
> +++ b/gcc/analyzer/store.cc
> @@ -259,6 +259,64 @@ bit_range::cmp (const bit_range &br1, const bit_range &br2)
> return wi::cmpu (br1.m_size_in_bits, br2.m_size_in_bits);
> }
>
> +/* If MASK is a contiguous range of set bits, write them
> + to *OUT and return true.
> + Otherwise return false. */
> +
> +bool
> +bit_range::from_mask (unsigned HOST_WIDE_INT mask, bit_range *out)
> +{
> + unsigned iter_bit_idx = 0;
> + unsigned HOST_WIDE_INT iter_bit_mask = 1;
> +
> + /* Find the first contiguous run of set bits in MASK. */
> +
> + /* Find first set bit in MASK. */
> + while (iter_bit_idx < HOST_BITS_PER_WIDE_INT)
> + {
> + if (mask & iter_bit_mask)
> + break;
> + iter_bit_idx++;
> + iter_bit_mask <<= 1;
> + }
> + if (iter_bit_idx == HOST_BITS_PER_WIDE_INT)
> + /* MASK is zero. */
> + return false;
> +
> + unsigned first_set_iter_bit_idx = iter_bit_idx;
> + unsigned num_set_bits = 1;
> + iter_bit_idx++;
> + iter_bit_mask <<= 1;
> +
> + /* Find next unset bit in MASK. */
> + while (iter_bit_idx < HOST_BITS_PER_WIDE_INT)
> + {
> + if (!(mask & iter_bit_mask))
> + break;
> + num_set_bits++;
> + iter_bit_idx++;
> + iter_bit_mask <<= 1;
> + }
> + if (iter_bit_idx == HOST_BITS_PER_WIDE_INT)
> + {
> + *out = bit_range (first_set_iter_bit_idx, num_set_bits);
> + return true;
> + }
> +
> + /* We now have the first contiguous run of set bits in MASK.
> + Fail if any other bits are set. */
> + while (iter_bit_idx < HOST_BITS_PER_WIDE_INT)
> + {
> + if (mask & iter_bit_mask)
> + return false;
> + iter_bit_idx++;
> + iter_bit_mask <<= 1;
> + }
> +
> + *out = bit_range (first_set_iter_bit_idx, num_set_bits);
> + return true;
> +}
> +
> /* class concrete_binding : public binding_key. */
>
> /* Implementation of binding_key::dump_to_pp vfunc for concrete_binding. */
> @@ -2448,6 +2506,132 @@ store::loop_replay_fixup (const store *other_store,
>
> namespace selftest {
>
> +/* Verify that bit_range::intersects_p works as expected. */
> +
> +static void
> +test_bit_range_intersects_p ()
> +{
> + bit_range b0 (0, 1);
> + bit_range b1 (1, 1);
> + bit_range b2 (2, 1);
> + bit_range b3 (3, 1);
> + bit_range b4 (4, 1);
> + bit_range b5 (5, 1);
> + bit_range b6 (6, 1);
> + bit_range b7 (7, 1);
> + bit_range b1_to_6 (1, 6);
> + bit_range b0_to_7 (0, 8);
> + bit_range b3_to_5 (3, 3);
> + bit_range b6_to_7 (6, 2);
> +
> + /* self-intersection is true. */
> + ASSERT_TRUE (b0.intersects_p (b0));
> + ASSERT_TRUE (b7.intersects_p (b7));
> + ASSERT_TRUE (b1_to_6.intersects_p (b1_to_6));
> + ASSERT_TRUE (b0_to_7.intersects_p (b0_to_7));
> +
> + ASSERT_FALSE (b0.intersects_p (b1));
> + ASSERT_FALSE (b1.intersects_p (b0));
> + ASSERT_FALSE (b0.intersects_p (b7));
> + ASSERT_FALSE (b7.intersects_p (b0));
> +
> + ASSERT_TRUE (b0_to_7.intersects_p (b0));
> + ASSERT_TRUE (b0_to_7.intersects_p (b7));
> + ASSERT_TRUE (b0.intersects_p (b0_to_7));
> + ASSERT_TRUE (b7.intersects_p (b0_to_7));
> +
> + ASSERT_FALSE (b0.intersects_p (b1_to_6));
> + ASSERT_FALSE (b1_to_6.intersects_p (b0));
> + ASSERT_TRUE (b1.intersects_p (b1_to_6));
> + ASSERT_TRUE (b1_to_6.intersects_p (b1));
> + ASSERT_TRUE (b1_to_6.intersects_p (b6));
> + ASSERT_FALSE (b1_to_6.intersects_p (b7));
> +
> + ASSERT_TRUE (b1_to_6.intersects_p (b0_to_7));
> + ASSERT_TRUE (b0_to_7.intersects_p (b1_to_6));
> +
> + ASSERT_FALSE (b3_to_5.intersects_p (b6_to_7));
> + ASSERT_FALSE (b6_to_7.intersects_p (b3_to_5));
> +}
> +
> +/* Implementation detail of ASSERT_BIT_RANGE_FROM_MASK_EQ. */
> +
> +static void
> +assert_bit_range_from_mask_eq (const location &loc,
> + unsigned HOST_WIDE_INT mask,
> + const bit_range &expected)
> +{
> + bit_range actual (0, 0);
> + bool ok = bit_range::from_mask (mask, &actual);
> + ASSERT_TRUE_AT (loc, ok);
> + ASSERT_EQ_AT (loc, actual, expected);
> +}
> +
> +/* Assert that bit_range::from_mask (MASK) returns true, and writes
> + out EXPECTED_BIT_RANGE. */
> +
> +#define ASSERT_BIT_RANGE_FROM_MASK_EQ(MASK, EXPECTED_BIT_RANGE) \
> + SELFTEST_BEGIN_STMT \
> + assert_bit_range_from_mask_eq (SELFTEST_LOCATION, MASK, \
> + EXPECTED_BIT_RANGE); \
> + SELFTEST_END_STMT
> +
> +/* Implementation detail of ASSERT_NO_BIT_RANGE_FROM_MASK. */
> +
> +static void
> +assert_no_bit_range_from_mask_eq (const location &loc,
> + unsigned HOST_WIDE_INT mask)
> +{
> + bit_range actual (0, 0);
> + bool ok = bit_range::from_mask (mask, &actual);
> + ASSERT_FALSE_AT (loc, ok);
> +}
> +
> +/* Assert that bit_range::from_mask (MASK) returns false. */
> +
> +#define ASSERT_NO_BIT_RANGE_FROM_MASK(MASK) \
> + SELFTEST_BEGIN_STMT \
> + assert_no_bit_range_from_mask_eq (SELFTEST_LOCATION, MASK); \
> + SELFTEST_END_STMT
> +
> +/* Verify that bit_range::from_mask works as expected. */
> +
> +static void
> +test_bit_range_from_mask ()
> +{
> + /* Should fail on zero. */
> + ASSERT_NO_BIT_RANGE_FROM_MASK (0);
> +
> + /* Verify 1-bit masks. */
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (1, bit_range (0, 1));
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (2, bit_range (1, 1));
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (4, bit_range (2, 1));
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (8, bit_range (3, 1));
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (16, bit_range (4, 1));
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (32, bit_range (5, 1));
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (64, bit_range (6, 1));
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (128, bit_range (7, 1));
> +
> + /* Verify N-bit masks starting at bit 0. */
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (3, bit_range (0, 2));
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (7, bit_range (0, 3));
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (15, bit_range (0, 4));
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (31, bit_range (0, 5));
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (63, bit_range (0, 6));
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (127, bit_range (0, 7));
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (255, bit_range (0, 8));
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (0xffff, bit_range (0, 16));
> +
> + /* Various other tests. */
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (0x30, bit_range (4, 2));
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (0x700, bit_range (8, 3));
> + ASSERT_BIT_RANGE_FROM_MASK_EQ (0x600, bit_range (9, 2));
> +
> + /* Multiple ranges of set bits should fail. */
> + ASSERT_NO_BIT_RANGE_FROM_MASK (0x101);
> + ASSERT_NO_BIT_RANGE_FROM_MASK (0xf0f0f0f0);
> +}
> +
> /* Implementation detail of ASSERT_OVERLAP. */
>
> static void
> @@ -2546,6 +2730,8 @@ test_binding_key_overlap ()
> void
> analyzer_store_cc_tests ()
> {
> + test_bit_range_intersects_p ();
> + test_bit_range_from_mask ();
> test_binding_key_overlap ();
> }
>
> diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h
> index be09b427366..7bd2824dba9 100644
> --- a/gcc/analyzer/store.h
> +++ b/gcc/analyzer/store.h
> @@ -297,8 +297,16 @@ struct bit_range
> && m_size_in_bits == other.m_size_in_bits);
> }
>
> + bool intersects_p (const bit_range &other) const
> + {
> + return (get_start_bit_offset () < other.get_next_bit_offset ()
> + && other.get_start_bit_offset () < get_next_bit_offset ());
> + }
> +
> static int cmp (const bit_range &br1, const bit_range &br2);
>
> + static bool from_mask (unsigned HOST_WIDE_INT mask, bit_range *out);
> +
> bit_offset_t m_start_bit_offset;
> bit_size_t m_size_in_bits;
> };
> @@ -338,6 +346,8 @@ public:
> const concrete_binding *dyn_cast_concrete_binding () const FINAL OVERRIDE
> { return this; }
>
> + const bit_range &get_bit_range () const { return m_bit_range; }
> +
> bit_offset_t get_start_bit_offset () const
> {
> return m_bit_range.m_start_bit_offset;
> @@ -739,6 +749,14 @@ public:
> get_concrete_binding (bit_offset_t start_bit_offset,
> bit_offset_t size_in_bits,
> enum binding_kind kind);
> + const concrete_binding *
> + get_concrete_binding (const bit_range &bits,
> + enum binding_kind kind)
> + {
> + return get_concrete_binding (bits.get_start_bit_offset (),
> + bits.m_size_in_bits,
> + kind);
> + }
> const symbolic_binding *
> get_symbolic_binding (const region *region,
> enum binding_kind kind);
> diff --git a/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c b/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c
> new file mode 100644
> index 00000000000..8bbe76bdbf3
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/analyzer/bitfields-1.c
> @@ -0,0 +1,144 @@
> +#include "analyzer-decls.h"
> +
> +typedef unsigned char u8;
> +typedef unsigned __INT16_TYPE__ u16;
> +typedef unsigned __INT32_TYPE__ u32;
> +
> +struct st1
> +{
> + u16 nonzero_offset;
> + unsigned int f0 : 1;
> + unsigned int f1 : 1;
> + unsigned int f2 : 1;
> + unsigned int f3 : 1;
> + unsigned int f4 : 1;
> + unsigned int f5 : 1;
> + unsigned int f6 : 1;
> + unsigned int f7 : 1;
> +};
> +
> +void test_1 (void)
> +{
> + struct st1 s;
> + s.f0 = 0;
> + __analyzer_eval (s.f0 == 0); /* { dg-warning "TRUE" } */
> + s.f0 = 1;
> + __analyzer_eval (s.f0 == 1); /* { dg-warning "TRUE" } */
> +
> + s.f1 = 0;
> + __analyzer_eval (s.f1 == 0); /* { dg-warning "TRUE" } */
> + s.f1 = 1;
> + __analyzer_eval (s.f1 == 1); /* { dg-warning "TRUE" } */
> +
> + /* etc */
> +
> + s.f6 = 0;
> + __analyzer_eval (s.f6 == 0); /* { dg-warning "TRUE" } */
> + s.f6 = 1;
> + __analyzer_eval (s.f6 == 1); /* { dg-warning "TRUE" } */
> +
> + s.f7 = 0;
> + __analyzer_eval (s.f7 == 0); /* { dg-warning "TRUE" } */
> + s.f7 = 1;
> + __analyzer_eval (s.f7 == 1); /* { dg-warning "TRUE" } */
> +};
> +
> +void test_2 (_Bool v0, _Bool v1, _Bool v2, _Bool v3,
> + _Bool v4, _Bool v5, _Bool v6, _Bool v7)
> +{
> + struct st1 s;
> + s.f0 = v0;
> + s.f1 = v1;
> + s.f2 = v2;
> + s.f3 = v3;
> + s.f4 = v4;
> + s.f5 = v5;
> + s.f6 = v6;
> + s.f7 = v7;
> +
> + __analyzer_eval (s.f0 == v0); /* { dg-warning "TRUE" } */
> + __analyzer_eval (s.f1 == v1); /* { dg-warning "TRUE" } */
> + __analyzer_eval (s.f2 == v2); /* { dg-warning "TRUE" } */
> + __analyzer_eval (s.f3 == v3); /* { dg-warning "TRUE" } */
> + __analyzer_eval (s.f4 == v4); /* { dg-warning "TRUE" } */
> + __analyzer_eval (s.f5 == v5); /* { dg-warning "TRUE" } */
> + __analyzer_eval (s.f6 == v6); /* { dg-warning "TRUE" } */
> + __analyzer_eval (s.f7 == v7); /* { dg-warning "TRUE" } */
> +};
> +
> +struct st3
> +{
> + unsigned int f01 : 2;
> + unsigned int f23 : 2;
> + unsigned int f34 : 2;
> + unsigned int f56 : 2;
> +};
> +
> +void test_3 (void)
> +{
> + struct st3 s;
> + s.f01 = 0;
> + __analyzer_eval (s.f01 == 0); /* { dg-warning "TRUE" } */
> + s.f01 = 1;
> + __analyzer_eval (s.f01 == 1); /* { dg-warning "TRUE" } */
> + s.f01 = 2;
> + __analyzer_eval (s.f01 == 2); /* { dg-warning "TRUE" } */
> + s.f01 = 3;
> + __analyzer_eval (s.f01 == 3); /* { dg-warning "TRUE" } */
> +
> + /* etc */
> +
> + s.f56 = 0;
> + __analyzer_eval (s.f56 == 0); /* { dg-warning "TRUE" } */
> + s.f56 = 1;
> + __analyzer_eval (s.f56 == 1); /* { dg-warning "TRUE" } */
> + s.f56 = 2;
> + __analyzer_eval (s.f56 == 2); /* { dg-warning "TRUE" } */
> + s.f56 = 3;
> + __analyzer_eval (s.f56 == 3); /* { dg-warning "TRUE" } */
> +};
> +
> +/* A signed bitfield. */
> +
> +struct st4
> +{
> + signed int f012 : 3;
> + signed int f345 : 3;
> +};
> +
> +void test_4 (void)
> +{
> + struct st4 s;
> + s.f345 = -4;
> + __analyzer_eval (s.f345 == -4); /* { dg-warning "TRUE" } */
> + s.f345 = -3;
> + __analyzer_eval (s.f345 == -3); /* { dg-warning "TRUE" } */
> + s.f345 = -2;
> + __analyzer_eval (s.f345 == -2); /* { dg-warning "TRUE" } */
> + s.f345 = -1;
> + __analyzer_eval (s.f345 == -1); /* { dg-warning "TRUE" } */
> + s.f345 = 0;
> + __analyzer_eval (s.f345 == 0); /* { dg-warning "TRUE" } */
> + s.f345 = 1;
> + __analyzer_eval (s.f345 == 1); /* { dg-warning "TRUE" } */
> + s.f345 = 2;
> + __analyzer_eval (s.f345 == 2); /* { dg-warning "TRUE" } */
> + s.f345 = 3;
> + __analyzer_eval (s.f345 == 3); /* { dg-warning "TRUE" } */
> +};
> +
> +/* A zero bitfield to break up padding. */
> +
> +struct st5
> +{
> + unsigned f0 : 5;
> + unsigned :0;
> + unsigned f1 : 16;
> +};
> +
> +void test_5 (void)
> +{
> + struct st5 s;
> + s.f1 = 0xcafe;
> + __analyzer_eval (s.f1 == 0xcafe); /* { dg-warning "TRUE" } */
> +}
> diff --git a/gcc/testsuite/gcc.dg/analyzer/data-model-1.c b/gcc/testsuite/gcc.dg/analyzer/data-model-1.c
> index c0f54637693..4a62a0e2bbc 100644
> --- a/gcc/testsuite/gcc.dg/analyzer/data-model-1.c
> +++ b/gcc/testsuite/gcc.dg/analyzer/data-model-1.c
> @@ -934,24 +934,20 @@ void test_43 (void)
>
> struct sbits
> {
> - int b0 : 1;
> - int b123 : 3;
> - int b456 : 3;
> - int b7 : 1;
> + signed int b0 : 1;
> + signed int b123 : 3;
> + signed int b456 : 3;
> + signed int b7 : 1;
> };
>
> void test_44 (void)
> {
> struct sbits bits;
> - bits.b0 = 1;
> - __analyzer_eval (bits.b0 == 1); /* { dg-warning "TRUE" "desired" { xfail *-*-* } } */
> - /* { dg-warning "FALSE" "status quo" { target *-*-* } .-1 } */
> - // TODO(xfail): ^^^^
> + bits.b0 = -1;
> + __analyzer_eval (bits.b0 == -1); /* { dg-warning "TRUE" } */
>
> - bits.b456 = 5;
> - __analyzer_eval (bits.b456 == 5); /* { dg-warning "TRUE" "desired" { xfail *-*-* } } */
> - /* { dg-warning "FALSE" "status quo" { target *-*-* } .-1 } */
> - // TODO(xfail): ^^^^
> + bits.b456 = -4;
> + __analyzer_eval (bits.b456 == -4); /* { dg-warning "TRUE" } */
> };
>
> struct ubits
> @@ -962,20 +958,14 @@ struct ubits
> unsigned int b7 : 1;
> };
>
> -/* FIXME: this requires BIT_FIELD_REF to work. */
> -
> void test_45 (void)
> {
> struct ubits bits;
> bits.b0 = 1;
> - __analyzer_eval (bits.b0 == 1); /* { dg-warning "TRUE" "desired, PR99212" { xfail { ! { cris-*-* } } } } */
> - /* { dg-warning "UNKNOWN" "status quo, PR99212" { target { *-*-* } xfail { cris-*-* } } .-1 } */
> - // TODO(xfail): ^^^^
> + __analyzer_eval (bits.b0 == 1); /* { dg-warning "TRUE" } */
>
> bits.b456 = 5;
> - __analyzer_eval (bits.b456 == 5); /* { dg-warning "TRUE" "desired" { xfail *-*-* } } */
> - /* { dg-warning "UNKNOWN" "status quo" { target *-*-* } .-1 } */
> - // TODO(xfail): ^^^^
> + __analyzer_eval (bits.b456 == 5); /* { dg-warning "TRUE" } */
> };
>
> extern const char *char_ptr;
> --
> 2.26.3
>
next prev parent reply other threads:[~2021-06-09 14:18 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-06-08 18:55 David Malcolm
2021-06-09 14:17 ` Christophe Lyon [this message]
2021-06-09 15:00 ` David Malcolm
2021-06-15 22:03 ` David Malcolm
2021-06-17 12:52 ` Christophe Lyon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAKdteOZ=fLDT8Sje7Kqgnoc0u3AfzS9daZxCr50Xixsa1TjFxQ@mail.gmail.com' \
--to=christophe.lyon@linaro.org \
--cc=dmalcolm@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).