From 567c7f82416530fe1f4aea7476cdd4f1f1ce327d Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 13 May 2020 17:59:57 -0400 Subject: [PATCH 131/179] FIXME: add POINTER_DIFF_EXPR and BIT_FIELD_REF, adding unknown_svalue2 for the latter --- gcc/analyzer/region-model2.cc | 74 +++++++++++++------- gcc/analyzer/region-model2.h | 13 ++-- gcc/testsuite/gcc.dg/analyzer/data-model-1.c | 14 ---- 3 files changed, 55 insertions(+), 46 deletions(-) diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc index 3e8b73c3896..3344a800b5c 100644 --- a/gcc/analyzer/region-model2.cc +++ b/gcc/analyzer/region-model2.cc @@ -365,6 +365,7 @@ region_svalue2::eval_condition (const region_svalue2 *lhs, const region2 *lhs_reg = lhs->get_pointee (); const region2 *rhs_reg = rhs->get_pointee (); bool ptr_equality = lhs_reg == rhs_reg; + // FIXME: what about when we have unknown values? /* TODO: what about child region2s where the child is the first child (or descendent)? Presumably we should look at base regions and compare offsets @@ -518,19 +519,16 @@ constant_svalue2::get_child_sval (region2 *parent ATTRIBUTE_UNUSED, /* class unknown_svalue2 : public svalue2. */ -/* Compare the fields of this unknown_svalue2 with OTHER, returning true - if they are equal. - For use by svalue2::operator==. */ -#if 0 -bool -unknown_svalue2::compare_fields (const unknown_svalue2 &) const +/* FIXME. */ + +void +unknown_svalue2::dump_to_pp (pretty_printer *pp, bool simple) const { - /* I *think* we want to return true here, in that when comparing - two region2 models, we want two peer unknown_svalue2 instances - to be the "same". */ - return true; + if (simple) + pp_printf (pp, "UNKNOWN"); + else + pp_printf (pp, "unknown_svalue2()"); } -#endif /* class poisoned_svalue2 : public svalue2. */ @@ -2577,6 +2575,9 @@ region_model2_manager::~region_model2_manager () for (constants_map_t::iterator iter = m_constants_map.begin (); iter != m_constants_map.end (); ++iter) delete (*iter).second; + for (unknowns_map_t::iterator iter = m_unknowns_map.begin (); + iter != m_unknowns_map.end (); ++iter) + delete (*iter).second; for (setjmp_values_map_t::iterator iter = m_setjmp_values_map.begin (); iter != m_setjmp_values_map.end (); ++iter) delete (*iter).second; @@ -3059,6 +3060,7 @@ region_model2_manager::log_stats (logger *logger, bool show_objs) const LOG_SCOPE (logger); logger->log ("svalue2 consolidation"); log_uniq_map (logger, show_objs, "constant_svalue2", m_constants_map); + log_uniq_map (logger, show_objs, "unknown_svalue2", m_unknowns_map); log_uniq_map (logger, show_objs, "poisoned_svalue2", m_poisoned_values_map); log_uniq_map (logger, show_objs, "setjmp_svalue2", m_setjmp_values_map); log_uniq_map (logger, show_objs, "initial_svalue2", m_initial_values_map); @@ -3711,14 +3713,6 @@ region_model2::on_gassign (const supernode */*snode*/, } break; -#if 0 - case BIT_FIELD_REF: - { - // TODO - } - break; -#endif - case CONSTRUCTOR: { if (TREE_CLOBBER_P (rhs1)) @@ -3764,23 +3758,28 @@ region_model2::on_gassign (const supernode */*snode*/, } break; -#if 0 case POINTER_DIFF_EXPR: { /* e.g. "_1 = p_2(D) - q_3(D);". */ + tree rhs2 = gimple_assign_rhs2 (assign); + const svalue2 *rhs1_sval = get_rvalue (rhs1, ctxt); + const svalue2 *rhs2_sval = get_rvalue (rhs2, ctxt); - /* TODO. */ + // TODO: perhaps fold to zero if they're known to be equal? - set_to_new_unknown_value (lhs_reg, TREE_TYPE (lhs), ctxt); + const svalue2 *sval_binop + = m_mgr->get_or_create_binop (TREE_TYPE (lhs), op, + rhs1_sval, rhs2_sval); + set_value (lhs_reg, sval_binop, ctxt); } break; -#endif /* Assignments of the form set_value (lvalue (LHS), rvalue (EXPR)) for various EXPR. We already have the lvalue for the LHS above, as "lhs_reg". */ case ADDR_EXPR: /* LHS = &RHS; */ + case BIT_FIELD_REF: case COMPONENT_REF: /* LHS = op0.op1; */ case MEM_REF: case REAL_CST: @@ -4992,6 +4991,28 @@ region_model2::get_rvalue_1 (path_var pv, } break; + case BIT_FIELD_REF: + { +#if 0 + tree expr = pv.m_tree; + const region2 *obj = get_lvalue (TREE_OPERAND (expr, 0), ctxt); + const svalue2 *num_bits = get_rvalue (TREE_OPERAND (expr, 1), ctxt); + const svalue2 *bit_offset = get_rvalue (TREE_OPERAND (expr, 2), ctxt); + /* FIXME: attempting to add bitwise access will ultimately require + a new svalue2 type for accessing bits from another svalue2 + (e.g. to handle the case where the store has no binding for the + bits), and probably a new region2 type also (or maybe just the + latter, using a sub_svalue2 for the former). + Is it possible to attempting to spot when we're accessing known + values, and have this possibly return NULL? */ + return maybe_get_store_bits (TREE_TYPE (expr), obj, num_bits, + bit_offset); +#else + return m_mgr->get_or_create_unknown_svalue2 (TREE_TYPE (pv.m_tree)); +#endif + } + break; + case SSA_NAME: case VAR_DECL: case PARM_DECL: @@ -7841,23 +7862,26 @@ test_region2_equality () } #endif -/* Verify that unary ops are folded as expected. */ +/* Verify that initial_svalue2 are handled as expected. */ static void test_initial_svalue2_folding () { region_model2_manager mgr; tree x = build_global_decl ("x", integer_type_node); + tree y = build_global_decl ("y", integer_type_node); test_region_model2_context ctxt; region_model2 model (&mgr); const svalue2 *x_init = model.get_rvalue (x, &ctxt); + const svalue2 *y_init = model.get_rvalue (y, &ctxt); + ASSERT_NE (x_init, y_init); const region2 *x_reg = model.get_lvalue (x, &ctxt); ASSERT_EQ (x_init, mgr.get_or_create_initial_value (x_reg)); } -/* Verify unary ops are folded as expected. */ +/* Verify that unary ops are folded as expected. */ static void test_unaryop_svalue2_folding () diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h index aceb7e9240a..91a2f0cfff0 100644 --- a/gcc/analyzer/region-model2.h +++ b/gcc/analyzer/region-model2.h @@ -183,8 +183,6 @@ public: dyn_cast_constant_svalue2 () const { return NULL; } virtual const poisoned_svalue2 * dyn_cast_poisoned_svalue2 () const { return NULL; } - virtual const unknown_svalue2 * - dyn_cast_unknown_svalue2 () const { return NULL; } virtual const setjmp_svalue2 * dyn_cast_setjmp_svalue2 () const { return NULL; } virtual const initial_svalue2 * @@ -302,6 +300,8 @@ is_a_helper ::test (const svalue2 *sval) namespace ana { +/* FIXME: in the new model, these are unknowable singletons, and comparing + them yields "unknown". */ /* Concrete subclass of svalue2 representing a unique but unknown value. Comparisons of variables that share the same unknown value are known to be equal, even if we don't know what the value is. */ @@ -315,11 +315,6 @@ public: enum kind get_kind () const FINAL OVERRIDE { return SK_UNKNOWN; } void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; - - const unknown_svalue2 * - dyn_cast_unknown_svalue2 () const FINAL OVERRIDE { return this; } - - private: }; #if 0 @@ -1566,6 +1561,7 @@ public: /* svalue2 consolidation. */ const svalue2 *get_or_create_constant_svalue2 (tree cst_expr); + const svalue2 *get_or_create_unknown_svalue2 (tree type); const svalue2 *get_or_create_setjmp_svalue2 (const setjmp_record &r, tree type); const svalue2 *get_or_create_poisoned_svalue2 (enum poison_kind kind, @@ -1636,6 +1632,9 @@ private: typedef hash_map constants_map_t; constants_map_t m_constants_map; + typedef hash_map unknowns_map_t; + unknowns_map_t m_unknowns_map; + typedef hash_map poisoned_values_map_t; poisoned_values_map_t m_poisoned_values_map; diff --git a/gcc/testsuite/gcc.dg/analyzer/data-model-1.c b/gcc/testsuite/gcc.dg/analyzer/data-model-1.c index 9439b2b553f..47423c3d742 100644 --- a/gcc/testsuite/gcc.dg/analyzer/data-model-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/data-model-1.c @@ -175,7 +175,6 @@ struct coord long y; }; -#if 0 int test_12d (struct coord c) { struct coord d; @@ -194,7 +193,6 @@ int test_12d (struct coord c) But d.x and d.y should be different unknown values (although they inherit from d's region). */ } -#endif /* Nested structs. */ @@ -472,7 +470,6 @@ void test_23 (struct foo *f, struct foo *g) __analyzer_eval (i == k); /* { dg-warning "UNKNOWN" } */ } -#if 0 void test_24 (struct foo *f) { struct foo g; @@ -486,9 +483,7 @@ void test_24 (struct foo *f) /* { dg-warning "TRUE" "status quo" { target *-*-* } .-1 } */ // TODO(xfail) } -#endif -#if 0 void test_25 (struct foo *f) { struct foo g; @@ -505,9 +500,7 @@ void test_25 (struct foo *f) /* { dg-warning "FALSE" "status quo" { target *-*-* } .-1 } */ // TODO(xfail) } -#endif -#if 0 void test_26 (struct coord *p, struct coord *q) { p->x = 42; @@ -531,7 +524,6 @@ void test_26 (struct coord *p, struct coord *q) __analyzer_eval (q->x); /* { dg-warning "UNKNOWN" } */ __analyzer_eval (q->y == 17); /* { dg-warning "TRUE" } */ } -#endif void test_27 (struct coord *p) { @@ -922,7 +914,6 @@ union u int *ptr; }; -#if 0 void test_41 (void) { union u u; @@ -935,7 +926,6 @@ void test_41 (void) __analyzer_eval (u.ptr == NULL); /* { dg-warning "TRUE" } */ __analyzer_eval (u.i == 42); /* { dg-warning "UNKNOWN" } */ } -#endif void test_42 (void) { @@ -988,7 +978,6 @@ struct ubits /* FIXME: this requires BIT_FIELD_REF to work. */ -#if 0 void test_45 (void) { struct ubits bits; @@ -1002,7 +991,6 @@ void test_45 (void) /* { dg-warning "UNKNOWN" "status quo" { target *-*-* } .-1 } */ // TODO(xfail): ^^^^ }; -#endif extern const char *char_ptr; @@ -1019,12 +1007,10 @@ char test_47 (void) return my_version[0]; } -#if 0 unsigned test_48 (unsigned char *p, unsigned char *q) { return (unsigned int)(p - q); } -#endif typedef struct { const char *filename; -- 2.21.0