From 5caa6468ed05c48c990c0835b10557ad20ec801b Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Tue, 5 May 2020 09:59:18 -0400 Subject: [PATCH 098/179] FIXME: add test_svalue2_folding --- gcc/analyzer/region-model2.cc | 180 ++++++++++++++++++++++++++++++++-- gcc/analyzer/region-model2.h | 5 + 2 files changed, 177 insertions(+), 8 deletions(-) diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc index 14e45f62537..d9c4fffa68c 100644 --- a/gcc/analyzer/region-model2.cc +++ b/gcc/analyzer/region-model2.cc @@ -2826,14 +2826,22 @@ region_model2_manager::get_ptr_svalue2 (tree ptr_type, region2 *pointee) } svalue2 * -region_model2_manager::get_or_create_unaryop (tree type, enum tree_code op, - svalue2 *arg) +region_model2_manager::maybe_fold_unaryop (tree type, enum tree_code op, + svalue2 *arg) { - /* Folding. */ + /* Constants. */ if (tree cst = arg->maybe_get_constant ()) if (tree result = fold_unary (op, type, cst)) return get_or_create_constant_svalue2 (result); + return NULL; +} +svalue2 * +region_model2_manager::get_or_create_unaryop (tree type, enum tree_code op, + svalue2 *arg) +{ + if (svalue2 *folded = maybe_fold_unaryop (type, op, arg)) + return folded; unaryop_svalue2::key_t key (type, op, arg); if (unaryop_svalue2 **slot = m_unaryop_values_map.get (key)) return *slot; @@ -2843,15 +2851,57 @@ region_model2_manager::get_or_create_unaryop (tree type, enum tree_code op, } svalue2 * -region_model2_manager::get_or_create_binop (tree type, enum tree_code op, - svalue2 *arg0, svalue2 *arg1) +region_model2_manager::maybe_fold_binop (tree type, enum tree_code op, + svalue2 *arg0, svalue2 *arg1) { - /* Folding. */ - if (tree cst0 = arg0->maybe_get_constant ()) - if (tree cst1 = arg1->maybe_get_constant ()) + tree cst0 = arg0->maybe_get_constant (); + tree cst1 = arg1->maybe_get_constant (); + /* (CST OP CST). */ + if (cst0 && cst1) + { if (tree result = fold_binary (op, type, cst0, cst1)) return get_or_create_constant_svalue2 (result); + } + if (FLOAT_TYPE_P (type) + || (arg0->get_type () && FLOAT_TYPE_P (arg0->get_type ())) + || (arg1->get_type () && FLOAT_TYPE_P (arg1->get_type ()))) + return NULL; + + switch (op) + { + default: + break; + case PLUS_EXPR: + /* (VAL + 0) -> VAL. */ + if (cst1 && zerop (cst1) && type == arg0->get_type ()) + return arg0; + /* (0 + VAL) -> VAL. */ + if (cst0 && zerop (cst0) && type == arg1->get_type ()) + return arg1; + break; + case MULT_EXPR: + /* (VAL * 0) or (0 * VAL) -> 0. */ + if ((cst1 && zerop (cst1)) || (cst0 && zerop (cst0))) + // FIXME: check for integer type + return get_or_create_constant_svalue2 (build_int_cst (type, 0)); + /* (VAL * 1) -> VAL. */ + if (cst1 && integer_onep (cst1) && type == arg0->get_type ()) + return arg0; + /* (1 * VAL) -> VAL. */ + if (cst0 && integer_onep (cst0) && type == arg1->get_type ()) + return arg1; + break; + } + return NULL; +} + +svalue2 * +region_model2_manager::get_or_create_binop (tree type, enum tree_code op, + svalue2 *arg0, svalue2 *arg1) +{ + if (svalue2 *folded = maybe_fold_binop (type, op, arg0, arg1)) + return folded; binop_svalue2::key_t key (type, op, arg0, arg1); if (binop_svalue2 **slot = m_binop_values_map.get (key)) return *slot; @@ -7527,7 +7577,118 @@ test_region2_equality () // TODO: test coverage for the map within a map_region2 } +#endif + +/* Verify that binops on constant svalues are folded. */ + +static void +test_svalue2_folding () +{ +#define NUM_CSTS 10 + tree cst_int[NUM_CSTS]; + region_model2_manager mgr; + svalue2 *cst_sval[NUM_CSTS]; + for (int i = 0; i < NUM_CSTS; i++) + { + cst_int[i] = build_int_cst (integer_type_node, i); + cst_sval[i] = mgr.get_or_create_constant_svalue2 (cst_int[i]); + ASSERT_EQ (cst_sval[i]->get_kind (), svalue2::SK_CONSTANT); + ASSERT_EQ (cst_sval[i]->maybe_get_constant (), cst_int[i]); + } + for (int i = 0; i < NUM_CSTS; i++) + for (int j = 0; j < NUM_CSTS; j++) + { + if (i != j) + ASSERT_NE (cst_sval[i], cst_sval[j]); + if (i + j < NUM_CSTS) + { + svalue2 *sum + = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR, + cst_sval[i], cst_sval[j]); + ASSERT_EQ (sum, cst_sval[i + j]); + } + if (i - j >= 0) + { + svalue2 *difference + = mgr.get_or_create_binop (integer_type_node, MINUS_EXPR, + cst_sval[i], cst_sval[j]); + ASSERT_EQ (difference, cst_sval[i - j]); + } + if (i * j < NUM_CSTS) + { + svalue2 *product + = mgr.get_or_create_binop (integer_type_node, MULT_EXPR, + cst_sval[i], cst_sval[j]); + ASSERT_EQ (product, cst_sval[i * j]); + } + svalue2 *eq = mgr.get_or_create_binop (integer_type_node, EQ_EXPR, + cst_sval[i], cst_sval[j]); + ASSERT_EQ (eq, i == j ? cst_sval[1] : cst_sval [0]); + svalue2 *neq = mgr.get_or_create_binop (integer_type_node, NE_EXPR, + cst_sval[i], cst_sval[j]); + ASSERT_EQ (neq, i != j ? cst_sval[1] : cst_sval [0]); + // etc + } + + 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); + svalue2 *x_init = model.get_rvalue (x, &ctxt); + region2 *x_reg = model.get_lvalue (x, &ctxt); + ASSERT_EQ (x_init, mgr.get_or_create_initial_value (x_reg)); + + /* PLUS_EXPR folding. */ + svalue2 *x_init_plus_zero + = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR, + x_init, cst_sval[0]); + ASSERT_EQ (x_init_plus_zero, x_init); + svalue2 *zero_plus_x_init + = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR, + cst_sval[0], x_init); + ASSERT_EQ (zero_plus_x_init, x_init); + + /* MULT_EXPR folding. */ + svalue2 *x_init_times_zero + = mgr.get_or_create_binop (integer_type_node, MULT_EXPR, + x_init, cst_sval[0]); + ASSERT_EQ (x_init_times_zero, cst_sval[0]); + svalue2 *zero_times_x_init + = mgr.get_or_create_binop (integer_type_node, MULT_EXPR, + cst_sval[0], x_init); + ASSERT_EQ (zero_times_x_init, cst_sval[0]); + + svalue2 *x_init_times_one + = mgr.get_or_create_binop (integer_type_node, MULT_EXPR, + x_init, cst_sval[1]); + ASSERT_EQ (x_init_times_one, x_init); + svalue2 *one_times_x_init + = mgr.get_or_create_binop (integer_type_node, MULT_EXPR, + cst_sval[1], x_init); + ASSERT_EQ (one_times_x_init, x_init); + + // etc + // TODO: do we want to use the match-and-simplify DSL for this? + + /* TODO: Verify that ((x + 1) + 1) == (x + 2). */ + svalue2 *x_init_plus_one + = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR, + x_init, cst_sval[1]); + svalue2 *x_init_plus_two + = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR, + x_init, cst_sval[2]); + svalue2 *x_init_plus_one_plus_one + = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR, + x_init_plus_one, cst_sval[1]); +#if 0 + ASSERT_EQ (x_init_plus_one_plus_one, x_init_plus_two); +#endif + + /* FIXME: do we want to canonicalize binops to put constants on the RHS ? */ +} +#if 0 /* A subclass of purge_criteria for selftests: purge all svalue2 *instances. */ class purge_all_svalue2_ids : public purge_criteria @@ -8878,6 +9039,9 @@ analyzer_region_model2_cc_tests () #if 0 test_svalue2_equality (); test_region2_equality (); +#endif + test_svalue2_folding (); +#if 0 test_purging_by_criteria (); test_purge_unused_svalue2s (); #endif diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h index 5d00c7d9bf0..9127c5ab9f3 100644 --- a/gcc/analyzer/region-model2.h +++ b/gcc/analyzer/region-model2.h @@ -1604,6 +1604,11 @@ public: region2 *create_region_for_alloca (frame_region2 *frame); private: + svalue2 *maybe_fold_unaryop (tree type, enum tree_code op, + svalue2 *arg); + svalue2 *maybe_fold_binop (tree type, enum tree_code op, + svalue2 *arg0, svalue2 *arg1); + unsigned m_next_region_id; root_region2 m_root_region; stack_region2 m_stack_region; -- 2.21.0