diff options
author | Mariam Arutunian <mariamarutunian@gmail.com> | 2023-01-05 19:37:00 +0400 |
---|---|---|
committer | Jeff Law <jlaw@ventanamicro> | 2023-03-21 09:03:20 -0600 |
commit | 483e48ae4fa536db3141fc95bde39deb8725ca5a (patch) | |
tree | 38daba79790990bed6d19f61a7d66dee445635e6 | |
parent | 5eff99fb3fbeab877740d75c2861983463618483 (diff) | |
download | gcc-483e48ae4fa536db3141fc95bde39deb8725ca5a.zip gcc-483e48ae4fa536db3141fc95bde39deb8725ca5a.tar.gz gcc-483e48ae4fa536db3141fc95bde39deb8725ca5a.tar.bz2 |
Changes in CRC detection v5:
- If before/after xor there is shift with other value than one, don't say it's not CRC.
- In the list of acceptable operations between xor and shift added minus and plus operations.
Changes in Traverse and execute CRC function v9:
- Check INTEGER_CST case in assign statement
- Deleted gcc/symb-execute-all-paths.cc/h.
Changes in LFSR matching v5:
- Added check for crc^data^1 and crc^data^1 neighbor bits case.
- Refactored check_xor_right_1_case function.
Changes in LFSR creation v2:
- Added last_set_bit function, to get last set bit of the polynomial and create smaller LFSR if needed.
- Create crc_value without new, and don't delete.
- Delete lfsr at the end.
Added crc-25.c, crc-callerid.c, crc-cc1541.c tests.
-rw-r--r-- | gcc/crc_verification.cc | 46 | ||||
-rw-r--r-- | gcc/gimple-crc-optimization.cc | 18 | ||||
-rw-r--r-- | gcc/sym-exec/state.cc | 35 | ||||
-rw-r--r-- | gcc/symb-execute-all-paths.cc | 1436 | ||||
-rw-r--r-- | gcc/symb-execute-all-paths.h | 124 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/crc-25.c | 29 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/crc-callerid.c | 29 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/crc-cc1541.c | 16 |
8 files changed, 133 insertions, 1600 deletions
diff --git a/gcc/crc_verification.cc b/gcc/crc_verification.cc index eee3cb8..df01074 100644 --- a/gcc/crc_verification.cc +++ b/gcc/crc_verification.cc @@ -168,6 +168,12 @@ crc_symbolic_execution::execute_assign_statement (const gassign *gs) return true; return false; } + case INTEGER_CST: + { + if (current_state->do_assign (op1, lhs)) + return true; + return false; + } default: { if (dump_file) @@ -1291,30 +1297,42 @@ maybe_neighbour_vals_of_crc (symbolic_bit *curr_bit_val, } -/* Check the case when current bit's value is crc[]^1 or crc[]^data[]^1. */ +/* Check the case when current bit's value is crc[]^1 or crc[]^data[]^1. + Thus curr_xor_exp_left value is crc[] or crc[]^data[]. */ bool check_xor_right_1_case (value_bit *curr_xor_exp_left, value_bit *next_bit_val) { -/* The case when current bit's value is crc[]^1 or crc[]^data[]^1, - next bit's - crc[]. - There may not be ^ 0 case, as expressions are optimized. */ - if (is_a<symbolic_bit *> (next_bit_val)) + /* The case when current bit's value is crc[]^1. */ + if (is_a<symbolic_bit *> (curr_xor_exp_left)) { - if (is_a<symbolic_bit *> (curr_xor_exp_left)) + /* The case when current bit's value is crc[]^1, + next bit's - crc[]. + There may not be ^ 0 case, as expressions are optimized. */ + if (is_a<symbolic_bit *> (next_bit_val)) return maybe_neighbour_vals_of_crc (as_a<symbolic_bit *> (curr_xor_exp_left), next_bit_val); - if (is_a<bit_xor_expression *> (curr_xor_exp_left)) - return maybe_neighbour_vals_of_crc (as_a<bit_xor_expression *> - (curr_xor_exp_left), - next_bit_val); + + if (is_a<bit_xor_expression *> (next_bit_val)) + { + bit_xor_expression *next_bit_xor + = as_a<bit_xor_expression *> (next_bit_val); + /* Check the case when current bit's value is crc[]^1, + next bit's something ^ 1. */ + if (is_a<bit *> ( + next_bit_xor->get_right ())) + return maybe_neighbour_vals_of_crc (as_a<symbolic_bit *> + (curr_xor_exp_left), + next_bit_xor->get_left ()); + } } - /* The case when current bit's value is crc[]^data[]^1, - next bit's - crc[]^data[]. */ - else if (is_a<bit_xor_expression *> (curr_xor_exp_left) - && is_a<bit_xor_expression *> (next_bit_val)) + + /* The case when current bit's value is crc[]^data[]^1, + next bit's - crc[]^data[] or crc[]^1 or crc[]^data[]^1. */ + if (is_a<bit_xor_expression *> (curr_xor_exp_left) + && is_a<bit_xor_expression *> (next_bit_val)) return maybe_neighbour_vals_of_crc (as_a<bit_xor_expression *> (curr_xor_exp_left), next_bit_val); diff --git a/gcc/gimple-crc-optimization.cc b/gcc/gimple-crc-optimization.cc index a792769..b362ea3 100644 --- a/gcc/gimple-crc-optimization.cc +++ b/gcc/gimple-crc-optimization.cc @@ -186,12 +186,13 @@ class crc_optimization { }; -/* TODO use existing code or move the function. +/* TODO: Move the function. Set GIMPLE_PHI and GIMPLE statements of the crc loop not visited. */ void set_loop_statements_not_visited (class loop *loop) { + // TODO: find faster way. basic_block *bbs = get_loop_body_in_dom_order (loop); for (unsigned int i = 0; i < loop->num_nodes; i++) { @@ -215,7 +216,7 @@ set_loop_statements_not_visited (class loop *loop) } -/* TODO use existing code or move the function. +/* TODO: Move the function. Set GIMPLE_PHI and GIMPLE statements of the function not visited. */ static void @@ -517,6 +518,8 @@ crc_optimization::is_acceptable_statement (const tree_code &stmt_code) return stmt_code == BIT_IOR_EXPR || stmt_code == BIT_AND_EXPR || stmt_code == BIT_XOR_EXPR + || stmt_code == MINUS_EXPR + || stmt_code == PLUS_EXPR || TREE_CODE_CLASS (stmt_code) == tcc_unary; } @@ -563,15 +566,6 @@ crc_optimization::can_not_be_shift_of_crc (gimple *assign_stmt, } return false; } - else - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, - "Found shift, but not with 1, not crc.\n"); - clean_xor_maybe_crc = false; - return true; - } - } /* No need for more strict checks, not CRCs may be filtered by the verification stage. */ @@ -985,6 +979,8 @@ crc_optimization::execute (function *fun) if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Returned state and LFSR differ.\n"); } + + delete lfsr; } return 0; } diff --git a/gcc/sym-exec/state.cc b/gcc/sym-exec/state.cc index 8b0560a..15b74ce 100644 --- a/gcc/sym-exec/state.cc +++ b/gcc/sym-exec/state.cc @@ -1981,6 +1981,16 @@ state::do_cast (tree var, tree dest, size_t cast_size) return true; } +/* Get the last 1 bit index. */ +size_t +last_set_bit (const value &polynomial) +{ + for (size_t i = 0; i < polynomial.length (); ++i) + { + if (as_a<bit *> (polynomial[polynomial.length () - i - 1])->get_val ()) + return polynomial.length () - i - 1; + } +} /* Create LFSR value for the reversed CRC. */ @@ -1988,7 +1998,9 @@ void state::create_reversed_lfsr (value &lfsr, const value &crc, const value &polynomial) { - size_t size = crc.length (); + /* Get the minimal byte size to keep the polynomial. + Ie, if the last 1 bit of the polynomial is at 6 index, size will be 8. */ + size_t size = ((last_set_bit (polynomial)/8) + 1) * 8; /* Determine values of all bits, except MSB. */ for (size_t i = 0; i < size - 1; i++) @@ -2038,10 +2050,8 @@ value * state::create_lfsr (tree crc, value *polynomial, bool is_bit_forward) { /* Check size compatibility․ */ - unsigned HOST_WIDE_INT - size = polynomial->length (); - unsigned HOST_WIDE_INT - crc_size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (crc))); + unsigned HOST_WIDE_INT size = polynomial->length (); + unsigned HOST_WIDE_INT crc_size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (crc))); if (crc_size < size) { if (dump_file && (dump_flags & TDF_DETAILS)) @@ -2052,24 +2062,19 @@ state::create_lfsr (tree crc, value *polynomial, bool is_bit_forward) } /* Create vector of symbolic bits for crc. */ - value *crc_value = new value (size, TYPE_UNSIGNED (TREE_TYPE (crc))); + value crc_value (size, TYPE_UNSIGNED (TREE_TYPE (crc))); - for (unsigned HOST_WIDE_INT i = 0; i < size; - i++) - crc_value->push (new symbolic_bit (i, crc)); + for (unsigned HOST_WIDE_INT i = 0; i < size; i++) + crc_value.push (new symbolic_bit (i, crc)); /* create LFSR vector. */ value *lfsr = new value (size, TYPE_UNSIGNED (TREE_TYPE (crc))); /* Calculate values for LFSR. */ if (is_bit_forward) - create_forward_lfsr (*lfsr, *crc_value, *polynomial); + create_forward_lfsr (*lfsr, crc_value, *polynomial); else - create_reversed_lfsr (*lfsr, *crc_value, *polynomial); - - /* crc_value is no more needed, delete. */ - free_val (crc_value); - delete crc_value; + create_reversed_lfsr (*lfsr, crc_value, *polynomial); return lfsr; } diff --git a/gcc/symb-execute-all-paths.cc b/gcc/symb-execute-all-paths.cc deleted file mode 100644 index 5f0d504..0000000 --- a/gcc/symb-execute-all-paths.cc +++ /dev/null @@ -1,1436 +0,0 @@ -/* - Execute symbolically all paths of the function. Iterate loops only once․ - Copyright (C) 2006-2022 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#include "symb-execute-all-paths.h" -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "backend.h" -#include "tree.h" -#include "gimple.h" -#include "tree-pass.h" -#include "ssa.h" -#include "gimple-iterator.h" -#include "tree-cfg.h" -#include "tree-ssa-loop-niter.h" -#include "cfgloop.h" -#include "gimple-range.h" -#include "tree-scalar-evolution.h" -#include "hwint.h" -#include "gimple-pretty-print.h" -#include "function.h" -#include "cfganal.h" - -/* This function assigns symbolic values to the arguments of the fun. - (Not complete). */ -bool -crc_symb_execution::make_symbolic_func_args_and_sizes (function *fun, - state *initial_state) -{ - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "\nMaking symbolic function's following arguments:\n"); - /* Get size and name of function's arguments. */ - for (tree arg = DECL_ARGUMENTS (fun->decl); arg; arg = DECL_CHAIN (arg)) - { - /* If the argument has a name and the size is integer - print that information. */ - if (TREE_CODE (DECL_SIZE (arg)) == INTEGER_CST && DECL_NAME (arg)) - { - unsigned HOST_WIDE_INT size = tree_to_uhwi (DECL_SIZE (arg)); - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "%s : %lu; ", - IDENTIFIER_POINTER (DECL_NAME (arg)), size); - /* Add argument with its size to the state - and assign symbolic value. */ - initial_state->make_symbolic (arg, size); - } - else if (dump_file) - fprintf (dump_file, "Argument not const or no name.\n"); - } - return true; -} - -/* Add declared ssa variables to the state. */ -bool -crc_symb_execution::add_function_local_ssa_vars (function *fun, - state *initial_state) -{ - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "\n\nAdding following ssa name declarations: \n"); - unsigned ix; - tree name; - /* Get ssa names of the function. - Check type, add to the state with a size length array value. */ - FOR_EACH_SSA_NAME (ix, name, fun) - { - if (TREE_CODE (TREE_TYPE (name)) == INTEGER_TYPE) - { - if (TYPE_UNSIGNED (TREE_TYPE (name))) - { - // We need this info for symb execution. - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, - "Unsigned, "); - } - } - else if (TREE_CODE (TREE_TYPE (name)) == POINTER_TYPE) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Pointer type, "); - } - else - { - /* Other type of variables aren't needed for CRC calculation. */ - if (dump_file && (dump_flags & TDF_DETAILS)) - { - print_generic_expr (dump_file, name, dump_flags); - fprintf (dump_file, ", %s type, won't be considered.\n", - get_tree_code_name (TREE_CODE (TREE_TYPE (name)))); - } - continue; - } - - unsigned HOST_WIDE_INT size - = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (name))); - - if (dump_file && (dump_flags & TDF_DETAILS)) - { - print_generic_expr (dump_file, name, dump_flags); - fprintf (dump_file, " size is %lu.\n", size); - } - - /* Add ssa variable with its size to the state, - assign symbolic value. */ - initial_state->make_symbolic (name, size); - } - return true; -} - -/* Calculate value of the rhs operation and assign to lhs variable. */ -bool -crc_symb_execution::execute_assign_statement (const gassign *gs) -{ - enum tree_code rhs_code = gimple_assign_rhs_code (gs); - tree lhs = gimple_assign_lhs (gs); - state *current_state = states.last (); - - if (gimple_num_ops (gs) == 2) - { - tree op1 = gimple_assign_rhs1 (gs); - switch (rhs_code) - { - case BIT_NOT_EXPR: - if (current_state->do_complement (op1, lhs)) - return true; - return false; - case MEM_REF: - /* FIXME: There can be something like - MEM[(some_type *)data + 1B], - in this case we just pass data. */ - if (current_state->do_mem_ref (TREE_OPERAND (op1, 0), lhs)) - return true; - return false; - case NOP_EXPR: - if (current_state->do_assign (op1, lhs)) - return true; - return false; - case SSA_NAME: - if (current_state->do_assign (op1, lhs)) - return true; - return false; - case VAR_DECL: - if (current_state->do_assign (op1, lhs)) - return true; - return false; - default: - if (dump_file) - fprintf (dump_file, - "Warning, encountered unsupported unary operation " - "with %s code while executing assign statement!\n", - get_tree_code_name (rhs_code)); - return false; - } - } - else if (gimple_num_ops (gs) == 3) - { - tree op1 = gimple_assign_rhs1 (gs); - tree op2 = gimple_assign_rhs2 (gs); - switch (rhs_code) - { - case LSHIFT_EXPR: - if (current_state->do_shift_left (op1, op2, lhs)) - return true; - return false; - case RSHIFT_EXPR: - if (current_state->do_shift_right (op1, op2, lhs)) - return true; - return false; - case BIT_AND_EXPR: - if (current_state->do_and (op1, op2, lhs)) - return true; - return false; - case BIT_IOR_EXPR: - if (current_state->do_or (op1, op2, lhs)) - return true; - return false; - case BIT_XOR_EXPR: - if (current_state->do_xor (op1, op2, lhs)) - return true; - return false; - case PLUS_EXPR: - if (current_state->do_add (op1, op2, lhs)) - return true; - return false; - case MINUS_EXPR: - if (current_state->do_sub (op1, op2, lhs)) - return true; - return false; - case MULT_EXPR: - if (current_state->do_mul (op1, op2, lhs)) - return true; - return false; - case POINTER_PLUS_EXPR: - if (current_state->do_pointer_plus (op1, op2, lhs)) - return true; - return false; - case POINTER_DIFF_EXPR: - if (current_state->do_pointer_diff (op1, op2, lhs)) - return true; - return false; - default: - if (dump_file) - fprintf (dump_file, - "Warning, encountered unsupported binary operation " - "with %s code while executing assign statement!\n", - get_tree_code_name (rhs_code)); - return false; - } - } - else - { - if (dump_file) - fprintf (dump_file, - "Warning, encountered unsupported operation, " - "with %s code while executing assign statement!\n", - get_tree_code_name (rhs_code)); - return false; - } - return true; -} - -/* If the next block of the edge1 dest is a back edge, add in the stack edge2. - Otherwise, add edge1 (the real execution path). - - When loop counter is checked in the if condition, - we mustn't continue on real path, - as we don't want to iterate the loop second time. */ -void add_edge (edge edge1, edge edge2, auto_vec<edge, 20>& stack) -{ - edge next_bb_edge = EDGE_SUCC (edge1->dest, 0); - if (next_bb_edge && (next_bb_edge->flags & EDGE_DFS_BACK)) - { - // FIXME: Compared variable's value will be incorrect, - // not satisfiable for the path. - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Won't iterate loop once more.\n"); - stack.quick_push (edge2); - } - else - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Adding the edge into the stack.\n"); - - /* If the result of the condition is true/false, - continue execution only by the true branch. */ - stack.quick_push (edge1); - } -} - -/* Add next basic blocks of the conditional block - for the execution path into the stack. - If the condition depends on symbolic values, keep both edges. - If the condition is true, keep true edge, else - false edge. */ -void crc_symb_execution::add_next_bbs (basic_block cond_bb, - state *new_branch_state, - auto_vec<edge, 20>& stack) -{ - edge true_edge; - edge false_edge; - extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge); - - if (new_branch_state->get_last_cond_status () == CS_SYM) - { - - /* Add true branch's state into the states. - False branch's states will be kept in the current state. */ - states.quick_push (new_branch_state); - - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Adding true and false edges into the stack.\n"); - - /* Add outgoing edges to the stack. */ - stack.quick_push (false_edge); - stack.quick_push (true_edge); - - return; - } - else if (new_branch_state->get_last_cond_status () == CS_TRUE) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Condition is true.\n"); - add_edge (true_edge, false_edge, stack); - } - else if (new_branch_state->get_last_cond_status () == CS_FALSE) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Condition is false.\n"); - add_edge (false_edge, true_edge, stack); - } - else - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Something went wrong " - "during handling conditional statement.\n"); - } - - /* When we continue execution of only one path, - there's no need of new state. */ - delete new_branch_state; -} - -/* Keep conditions depending on symbolic variables in the states. */ -bool crc_symb_execution::add_condition (const gcond* cond, - state* current_state, - state* new_branch_state) -{ - /* Keep conditions of each branch execution in its state. - Ex. - if (a == 0) // a's value is unknown - - new_branch_state.keep (a==0) - current_state.keep (a!=0) - */ - - tree lhs = gimple_cond_lhs (cond); - tree rhs = gimple_cond_rhs (cond); - switch (gimple_cond_code (cond)) - { - case EQ_EXPR: - new_branch_state->add_equal_cond (lhs, rhs); - if (new_branch_state->get_last_cond_status () == CS_SYM) - current_state->add_not_equal_cond (lhs, rhs); - return true; - case NE_EXPR: - new_branch_state->add_not_equal_cond (lhs, rhs); - if (new_branch_state->get_last_cond_status () == CS_SYM) - current_state->add_equal_cond (lhs, rhs); - return true; - case GT_EXPR: - new_branch_state->add_greater_than_cond (lhs, rhs); - if (new_branch_state->get_last_cond_status () == CS_SYM) - current_state->add_less_or_equal_cond (lhs, rhs); - return true; - case LT_EXPR: - new_branch_state->add_less_than_cond (lhs, rhs); - if (new_branch_state->get_last_cond_status () == CS_SYM) - current_state->add_greater_or_equal_cond (lhs, rhs); - return true; - case GE_EXPR: - new_branch_state->add_greater_or_equal_cond (lhs, rhs); - if (new_branch_state->get_last_cond_status () == CS_SYM) - current_state->add_less_than_cond (lhs, rhs); - return true; - case LE_EXPR: - new_branch_state->add_less_or_equal_cond (lhs, rhs); - if (new_branch_state->get_last_cond_status () == CS_SYM) - current_state->add_greater_than_cond (lhs, rhs); - return true; - default: - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Unsupported condition.\n"); - return false; - } -} - -/* Create new state for true and false branch. - Keep conditions in new created states. */ -bool -crc_symb_execution::resolve_condition (const gcond* cond, - auto_vec<edge, 20>& stack) -{ - /* Remove last state. */ - state* current_state = states.last (); - state* new_branch_state = new state (*current_state); - - if (!add_condition (cond, current_state, new_branch_state)) - return false; - - add_next_bbs (cond->bb, new_branch_state, stack); - return true; -} - -/* Keep the calculated value of the return value - and the conditions of the executed path. */ -bool -crc_symb_execution::keep_return_val_and_conditions (const greturn* ret) -{ - tree return_op = gimple_return_retval (ret); - - if (!return_op) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "No return value.\n"); - return false; - } - - if (TREE_CODE (return_op) == INTEGER_CST) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Return value is a constant.\n"); - return false; - } - - /* Get calculated return value. */ - state * curr_state = states.last (); - value * return_value = curr_state->get_value (return_op); - - if (!return_value) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Return value is not in the state.\n"); - return false; - } - - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Return value is "); - state::print_value (return_value); - } - - state * final_state = new state; - - /* Keep return value's calculated value and conditions in the final state. */ - final_state->add_var_state (return_op, return_value); - final_state->bulk_add_conditions (curr_state->get_conditions ()); - final_states.quick_push (final_state); - - delete curr_state; - states.pop (); - - return true; -} - - -/* Execute gimple statements of BB. - Keeping values of variables in the state. */ -bool -crc_symb_execution::execute_bb_gimple_statements (basic_block bb, - auto_vec<edge, 20>& stack) -{ - for (gimple_stmt_iterator bsi = gsi_start_bb (bb); - !gsi_end_p (bsi); gsi_next (&bsi)) - { - gimple *gs = gsi_stmt (bsi); - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Executing "); - print_gimple_stmt (dump_file, gs, dump_flags); - } - switch (gimple_code (gs)) - { - case GIMPLE_ASSIGN: - if (!execute_assign_statement (as_a<const gassign *> (gs))) - return false; - break; - case GIMPLE_COND: - if (!resolve_condition (as_a<const gcond *> (gs), stack)) - return false; - return true; - case GIMPLE_RETURN: - if (!keep_return_val_and_conditions (as_a<const greturn *> (gs))) - return false; - return true; - default: - if (dump_file) - fprintf (dump_file, - "Warning, encountered unsupported statement, " - "while executing gimple statements!\n"); - return false; - } - } - - /* Add each outgoing edge of the current block to the stack, - despite back edges. - This code isn't reachable if the last statement of the basic block - is a conditional statement or return statement. - Those cases are handled separately. */ - edge out_edge; - edge_iterator ei; - FOR_EACH_EDGE (out_edge, ei, bb->succs) - if (!(out_edge->flags & EDGE_DFS_BACK)) - stack.quick_push (out_edge); - else if (!states.is_empty ()) - { - /* Delete the state after executing the full path, - or encountering back edge. */ - delete states.last (); - states.pop (); - } - - return true; -} - -/* Assign values of phi instruction to its result. - Keep updated values in the state. */ -bool -crc_symb_execution::execute_bb_phi_statements (basic_block bb, - edge incoming_edge) -{ - for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi); - gsi_next (&gsi)) - { - gphi *phi = gsi.phi (); - tree lhs = gimple_phi_result (phi); - - /* Don't consider virtual operands. */ - if (virtual_operand_p (lhs)) - continue; - - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Determining the value " - "for the following phi.\n"); - print_gimple_stmt (dump_file, phi, dump_flags); - } - - tree rhs = PHI_ARG_DEF_FROM_EDGE (phi, incoming_edge); - - state *current_state = states.last (); - if (!current_state->do_assign (rhs, lhs)) - return false; - } - return true; -} - -/* Execute all statements of BB. - Keeping values of variables in the state. */ -bool -crc_symb_execution::execute_bb_statements (basic_block bb, - edge incoming_edge, - auto_vec<edge, 20> &stack) -{ - if (!execute_bb_phi_statements (bb, incoming_edge)) - return false; - - return execute_bb_gimple_statements (bb, stack); -} - -/* Traverse function fun's all paths from the first basic block to the last. - Each time iterate loops only once. - Symbolically execute statements of each path. */ -bool -crc_symb_execution::traverse_function (function *fun) -{ - /* TODO: Check whether back_edges can be determined by BB index, - if so, no need of EDGE_DFS_BACK flag. */ - mark_dfs_back_edges (fun); - /* Allocate stack for back-tracking up CFG. */ - auto_vec<edge, 20> stack (n_basic_blocks_for_fn (fun) + 1); - - /* Push all successor edges of first block into the stack. - No need to execute first block. */ - edge e; - edge_iterator ei; - FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs) - stack.quick_push (e); - - while (!stack.is_empty ()) - { - /* Look at the edge on the top of the stack. */ - edge e = stack.last (); - stack.pop (); - - /* Get dest block of the edge. */ - basic_block bb = e->dest; - - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "\n\nExecuting BB <%d>\n\n", bb->index); - - /* Symbolically execute statements. */ - if (!execute_bb_statements (bb, e, stack)) - return false; - } - return true; -} - -bool -crc_symb_execution::execute_function (function *fun) -{ - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "\nExecuting CRC-like function.\n"); - - /* Create initial state and push into the vector of states. */ - states.quick_push (new state); - state *initial_state = states.last (); - - make_symbolic_func_args_and_sizes (fun, initial_state); - - /* Add declared variables to the state. */ - add_function_local_ssa_vars (fun, initial_state); - - /* Execute function's statements, keeping a state for each path. */ - return traverse_function (fun); -} - -/* Determine which bit of data must be 1. */ -unsigned HOST_WIDE_INT -determine_index (tree data, bool is_shift_left) -{ - if (is_shift_left) - // FIXME: may be the data's size is larger, - // but MSB is checked for the middle bit. - return tree_to_uhwi (TYPE_SIZE (TREE_TYPE (data))) - 1; - else - return 0; -} - -/* Assign appropriate values to data, crc - and other phi results to calculate the polynomial. */ -void -assign_vals_to_header_phis (state *polynomial_state, basic_block bb, - gphi *crc, gphi *data, - bool is_shift_left) -{ - for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi); - gsi_next (&gsi)) - { - - gphi *phi = gsi.phi (); - tree lhs = gimple_phi_result (phi); - - /* Don't consider virtual operands. */ - if (virtual_operand_p (lhs)) - continue; - - if ((data && phi == data) || (!data && phi == crc)) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Assigning the required value to "); - print_generic_expr (dump_file, lhs, dump_flags); - fprintf (dump_file, " variable.\n"); - } - polynomial_state->do_assign_pow2 (lhs, - determine_index (lhs, - is_shift_left)); - } - else if (phi == crc) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Assigning 0 value to "); - print_generic_expr (dump_file, lhs, dump_flags); - fprintf (dump_file, " variable.\n"); - } - polynomial_state->do_assign (build_zero_cst (TREE_TYPE (lhs)), lhs); - } - else if (TREE_CODE (PHI_ARG_DEF (phi, phi->nargs - 1)) == INTEGER_CST) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "First value of phi is a constant, " - "assigning the number to "); - print_generic_expr (dump_file, lhs, dump_flags); - fprintf (dump_file, " variable.\n"); - } - polynomial_state->do_assign (PHI_ARG_DEF (phi, phi->nargs - 1), lhs); - } - else - { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "First value of phi isn't constant, " - "assigning to "); - print_generic_expr (dump_file, lhs, dump_flags); - fprintf (dump_file, " variable.\n"); - } - polynomial_state->do_assign (build_zero_cst (TREE_TYPE (lhs)), lhs); - } - } -} - - -/* Execute the loop, which calculates crc with initial values, - to calculate the polynomial. */ -bool -crc_symb_execution::execute_crc_loop (class loop *crc_loop, gphi *crc, - gphi *data, - bool is_shift_left) -{ - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "\n\nTrying to calculate the polynomial.\n\n"); - - states.quick_push (new state); - - basic_block bb = crc_loop->header; - assign_vals_to_header_phis (states.last (), bb, crc, data, is_shift_left); - - auto_vec<edge, 20> stack (crc_loop->num_nodes); - - execute_bb_gimple_statements (bb, stack); - - /* stack may not be empty. Successor BB's are added into the stack - from the execute_bb_gimple_statements function. */ - while (!stack.is_empty ()) - { - /* Look at the edge on the top of the stack. */ - edge e = stack.last (); - stack.pop (); - - /* Get dest block of the edge. */ - basic_block bb = e->dest; - - /* Execute only basic blocks of the crc_loop. */ - if (!flow_bb_inside_loop_p (crc_loop, bb)) - continue; - - - /* Execute statements. */ - if (!execute_bb_statements (bb, e, stack)) - return false; - } - - if (states.length () != 1) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "The number of states is not one.\n"); - return false; - } - return true; -} - - -/* Return true if all bits of the polynomial are constants (0 or 1). - Otherwise return false. */ -bool polynomial_is_known (const value * polynomial) -{ - for (size_t i = 0; i < polynomial->length (); i++) - { - if (!is_a<bit *> ((*polynomial)[i])) - return false; - } - return true; -} - - -/* Execute the loop, which is expected to calculate CRC, - to extract polynomial, assigning real numbers to crc and data. */ -value * -crc_symb_execution::extract_poly_and_create_lfsr (class loop *crc_loop, - gphi *crc, gphi *data, - bool is_shift_left) -{ - if (!execute_crc_loop (crc_loop, crc, data, is_shift_left)) - return nullptr; - - state *polynomial_state = states.last (); - - /* Get the tree which will contain the value of the polynomial - at the end of the loop. */ - tree calculated_crc = PHI_ARG_DEF (crc, 0); - - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Getting the value of "); - print_generic_expr (dump_file, calculated_crc, dump_flags); - fprintf (dump_file, " variable.\n"); - } - - /* Get the value (bit vector) of the tree (it may be the polynomial). */ - value * polynomial = polynomial_state->get_value (calculated_crc); - if (!polynomial) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Polynomial's value is null"); - return nullptr; - } - - if (dump_file && (dump_flags & TDF_DETAILS)) - { - /* Note: It may not be the real polynomial. - If it's a bit reflected crc, - then to get a real polynomial, - it must be reflected and 1 bit added. */ - fprintf (dump_file, "Polynomial's value is "); - state::print_value (polynomial); - } - - /* Check that polynomial's all bits are constants. */ - if (!polynomial_is_known (polynomial)) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Polynomial's value is not constant.\n"); - } - return nullptr; - } - - return state::create_lfsr (calculated_crc, polynomial, is_shift_left); -} - - -/* Returns true if index1 and index2 differ by a factor of 8. */ -bool acceptable_diff (size_t index1, size_t index2) -{ - size_t diff; - if (index1 > index2) - diff = index1 - index2; - else - diff = index2 - index1; - - /* Indexes of the symbolic bit may differ by 0, 8, 16, 24, 32, ... */ - return diff % 8 == 0; -} - -/* Check whether the condition_exp and refernce_exp match. */ -bool -may_be_xors_condition (value_bit *reference_exp, value_bit *condition_exp, - size_t sb_index) -{ - if (!reference_exp) - return false; - - if (!condition_exp) - return false; - - if (is_a<symbolic_bit *> (reference_exp) - && is_a<symbolic_bit *> (condition_exp)) - { - symbolic_bit *condition_symbolic = as_a<symbolic_bit *> (condition_exp); - symbolic_bit *reference_symbolic = as_a<symbolic_bit *> (reference_exp); - return reference_symbolic->get_origin () - == condition_symbolic->get_origin () - && acceptable_diff (sb_index, - condition_symbolic->get_index ()); - } - if (is_a<symbolic_bit *> (reference_exp) - && is_a<bit_xor_expression *> (condition_exp)) - { - return may_be_xors_condition (as_a<symbolic_bit *> (reference_exp), - as_a<bit_xor_expression *> - (condition_exp)->get_left (), sb_index) - || may_be_xors_condition (as_a<symbolic_bit *> (reference_exp), - as_a<bit_xor_expression *> - (condition_exp)->get_right (), - sb_index); - } - if (is_a<bit_xor_expression *> (reference_exp) - && is_a<bit_xor_expression *> (condition_exp)) - { - return may_be_xors_condition (as_a<bit_xor_expression *> - (reference_exp)->get_left (), - as_a<bit_xor_expression *> - (condition_exp)->get_left (), sb_index) - && may_be_xors_condition (as_a<bit_xor_expression *> - (reference_exp)->get_right (), - as_a<bit_xor_expression *> - (condition_exp)->get_right (), - sb_index); - } - return false; -} - - -/* Checks whether the condition is checked for significant bit being 0 or 1. - If is_one is 1, when check whether the significant bit is 1 (xor branch), - if 0 whether the significant bit is 0 (not xor branch). */ -bool -check_condition (value_bit *symb_exp, unsigned char is_one, - size_t sb_index, state *final_state) -{ - for (auto iter = final_state->get_conditions ().begin (); - iter != final_state->get_conditions ().end (); ++iter) - { - bit_condition * condition = nullptr; - - if (is_a <bit_condition *> (*iter)) - condition = as_a <bit_condition *> (*iter); - else - continue; - - value_bit *cond_exp = (*iter)->get_left (); - if (may_be_xors_condition (symb_exp, cond_exp, sb_index)) - { - if (!is_a <bit *> ((*iter)->get_right ())) - return false; - - unsigned char comparison_val = as_a <bit *> ((*iter)->get_right ()) - ->get_val (); - if (condition->get_cond_type () == EQ_EXPR) - return comparison_val == is_one; - if (condition->get_cond_type () == NE_EXPR) - return comparison_val != is_one; - return false; - } - } - return false; -} - - -/* Returns true if the symb_exp is a bit_xor_expression and const_bit equals 1. - Otherwise, returns false. */ -bool -is_one (value_bit *const_bit) -{ - return is_a<bit *> (const_bit) - && (as_a<bit *> (const_bit))->get_val () == 1; -} - - -/* Returns true if bit is symbolic and its index differs from LFSR bit's index - by a factor of 8. - Sometimes calculated crc value is returned - after being shifted by 8's factor. */ -bool -is_a_valid_symb (value_bit *bit, size_t lfsr_bit_index) -{ - if (!is_a<symbolic_bit *> (bit)) - return false; - - size_t sym_bit_index = (as_a<symbolic_bit *> (bit))->get_index (); - return acceptable_diff (sym_bit_index, lfsr_bit_index); -} - - -/* Returns true if bit is crc[index+8*i]^data[index+8*i], - where i is a whole number. - Otherwise, returns false. */ -bool -is_a_valid_xor (value_bit *bit, size_t lfsr_bit_index) -{ - return is_a<bit_xor_expression *> (bit) - && is_a_valid_symb ((as_a<bit_xor_expression *> (bit))->get_left (), - lfsr_bit_index) - && is_a_valid_symb ((as_a<bit_xor_expression *> (bit))->get_right (), - lfsr_bit_index); -} - - -/* Returns true if the bit is a valid - crc[index+8*i] ^ data[index+8*i] ^ 1, or crc[index+8*i] ^ 1, - where i is a whole number. - index is the index of the LFSR bit from the same position as in CRC. - - If there is lfsr[8] at LFSR value vectors' 9-th bit, - when in the crc vectors' 9-th bit's value we must be - crc[8] or maybe crc[16],... - - Otherwise, returns false. */ -bool -is_a_valid_xor_one (value_bit *bit, size_t lfsr_bit_index) -{ - if (is_a<bit_xor_expression *> (bit)) - { - value_bit *symb_exp = nullptr; - bit_xor_expression *xor_exp = as_a<bit_xor_expression *> (bit); - if (is_one (xor_exp->get_right ())) - symb_exp = xor_exp->get_left (); - else if (is_one (xor_exp->get_left ())) - symb_exp = xor_exp->get_right (); - else - return false; - return is_a_valid_xor (symb_exp, lfsr_bit_index) - || is_a_valid_symb (symb_exp, lfsr_bit_index); - } - else - return false; -} - - -/* Check whether LSB/MSB of LFSR and calculated (maybe)CRC match. */ -bool -significant_bits_match (value_bit *crc, value_bit *lfsr, - value_bit *conditions_crc, - size_t sb_index, state *final_state) -{ - /* If LFSR's MSB/LSB value is a constant (0 or 1), - then CRC's MSB/LSB must have the same value. */ - if (is_a<bit *> (lfsr)) - { - if (!((is_a<bit *> (crc) - && as_a<bit *> (crc)->get_val () - == as_a<bit *> (lfsr)->get_val ()))) - return false; - return true; - } - /* If LFSR's MSB/LSB value is a symbolic_bit - (that means MSB/LSB of the polynomial is 1), - then CRC's MSB/LSB must be 0 if the condition is false, - 1 - if the condition is true. - (Because crc is xored with the polynomial in case LSB/MSB is 1). */ - else if (is_a<symbolic_bit *> (lfsr)) - { - if (!(is_a<bit *> (crc) && ((as_a<bit *> (crc)->get_val () == 0 - && check_condition (conditions_crc, 0, - sb_index, final_state)) - || (as_a<bit *> (crc)->get_val () == 1 - && check_condition (conditions_crc, 1, - sb_index, - final_state))))) - return false; - return true; - } - return false; -} - -/* Check whether LSB/MSB of LFSR and calculated (maybe)CRC match. */ -bool -significant_bits_match (const value *lfsr, - const value *crc_state, - bool is_left_shift, - value_bit *symb_val, - size_t it_end, - state *final_state) -{ - if (is_left_shift) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Checking 0 bit.\n"); - - if (!significant_bits_match ((*crc_state)[0], (*lfsr)[0], symb_val, - it_end-1, final_state)) - return false; - } - else - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Checking %lu bit.\n", it_end); - - if (!significant_bits_match ((*crc_state)[it_end], - (*lfsr)[it_end], symb_val, 0, final_state)) - return false; - } - return true; -} - - -/* Match the crc to the lfsr, where crc's all bit values are bit_xor_expression - or bit_xor_expression ^ 1, besides MSB/LSB. - - Under this are considered the cases, - 1. When sizes of crc and data are same. - - 2. When data is xored with crc in the loop. */ -bool -match_lfsr_case2 (const value *lfsr, - const value *crc_state, - bit_xor_expression *symb_val, - bool is_left_shift, - size_t i, size_t it_end, size_t sb_index, - state *final_state) -{ - /* Check whether significant bits of LFSR and CRC match. */ - if (!significant_bits_match (lfsr, crc_state, is_left_shift, symb_val, - it_end, final_state)) - return false; - - for (; i < it_end; i++) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Checking %lu bit.\n", i); - - if (is_a<bit_xor_expression *> ((*lfsr)[i])) - { - size_t index = (as_a<bit_xor_expression *> ((*lfsr)[i]))->get_left () - ->get_index (); - if (!((is_a_valid_xor_one ((*crc_state)[i], index) - && check_condition ( - as_a<bit_xor_expression *> ((*crc_state)[i])->get_left (), - 1, sb_index, final_state)) - || (is_a_valid_xor ((*crc_state)[i], index) - && check_condition ((*crc_state)[i], 0, sb_index, - final_state)))) - return false; - } - else if (is_a<symbolic_bit *> ((*lfsr)[i])) - { - size_t index = (as_a<symbolic_bit *> ((*lfsr)[i]))->get_index (); - if (!(is_a_valid_xor ((*crc_state)[i], index) - && (check_condition ((*crc_state)[i], 0, sb_index, final_state) - || check_condition ((*crc_state)[i], 1, sb_index, - final_state)))) - return false; - } - else - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Not expected expression in LFSR.\n"); - return false; - } - } - return true; -} - - -/* Match the crc to the lfsr, where crc's all bit values are symbolic_bits - or symbolic_bits ^ 1, besides MSB/LSB (it may be constant). - - Under this are considered the cases, - 1. When sizes of crc and data are same. - - 2. When data is xored with crc before the loop. - 3. When data is xor-ed with crc only for the condition and - xor is done only on crc. */ -bool -match_lfsr_case1 (const value *lfsr, - const value *crc_state, - symbolic_bit *symb_val, - bool is_left_shift, - size_t i, size_t it_end, size_t sb_index, - state *final_state) -{ - - /* Check whether significant bits of LFSR and CRC match. */ - if (!significant_bits_match (lfsr, crc_state, is_left_shift, symb_val, - it_end, final_state)) - return false; - - for (; i < it_end; i++) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Checking %lu bit.\n", i); - - /* Check the case when in lfsr we have LFSR (i)^LFSR (SBi), - where 0<i<LFSR_size and SBi is the index of MSB/LSB (LFSR_size-1/0). - In that case in crc_state (resulting CRC) - we must have crc (i+8*k)^1 case, when condition is true - and crc (i+8*k) when condition is false, - (as crc is xor-ed with the polynomial only if the LSB/MSB is one) - where k is a whole number - (in some implementations crc is shifted left or right by 8, 16...). */ - if (is_a<bit_xor_expression *> ((*lfsr)[i])) - { - size_t index = (as_a<bit_xor_expression *> ((*lfsr)[i]))->get_left () - ->get_index (); - if (!((is_a_valid_xor_one ((*crc_state)[i], index) - && check_condition ( - as_a<bit_xor_expression *> ((*crc_state)[i])->get_left (), - 1, sb_index, final_state)) - || (is_a_valid_symb ((*crc_state)[i], index) - && check_condition ((*crc_state)[i], 0, sb_index, - final_state)))) - return false; - } - /* Check the case when in LFSR we have LFSR (i), where 0<i<LFSR_size. - In that case in resulting CRC we must have crc (i+8*k) case, - when condition is true or condition is false. - If we have just LFSR (i), that means polynomial's i+-1 bit is 0, - so despite CRC is xor-ed or not, we will have crc (i). */ - else if (is_a<symbolic_bit *> ((*lfsr)[i])) - { - size_t index = (as_a<symbolic_bit *> ((*lfsr)[i]))->get_index (); - if (!(is_a_valid_symb ((*crc_state)[i], index) - && (check_condition ((*crc_state)[i], 0, sb_index, final_state) - || check_condition ((*crc_state)[i], 1, sb_index, - final_state)))) - return false; - } - else - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Not expected expression in LFSR.\n"); - return false; - } - } - return true; -} - - -/* Returns true if in the CRC value's vector we have one of the form of - following consecutive bits - 1. 0, then 1 - 2. 1, then 0 - 3. 0, then 0 - 4. 1, then 1 - Otherwise returns false. - */ -bool -maybe_neighbour_vals_of_crc (bit *curr_bit_val, - value_bit *next_bit_val) -{ - if (!curr_bit_val) - return true; - - /* As the value doesn't matter, - just check that next_bit_val is bit *. */ - if (is_a<bit *> (next_bit_val)) - return true; - return false; -} - - -/* Returns true if in the CRC value's vector we have one of the form of - following consecutive bits - 1. crc[], then crc[] - 2. crc[], then crc[]^data[] - 3. crc[], then crc[]^data[]^1 - 4. crc[], then crc[]^1 - 5. data[], then crc[]^data[] - 6. data[], then crc[]^data[]^1 - 7. crc[], then crc[]^data1[]^data2[] TODO: Maybe needs a correction. - ... - Otherwise returns false. */ -bool -maybe_neighbour_vals_of_crc (symbolic_bit *curr_bit_val, - value_bit *next_bit_val) -{ - if (!curr_bit_val) - return true; - - /* If both are symbolic_bits, - check that they are bits of the same variable. */ - if (is_a<symbolic_bit *> (next_bit_val)) - { - return curr_bit_val->get_origin () - == as_a<symbolic_bit *> (next_bit_val)->get_origin (); - } - else if (is_a<bit_xor_expression *> (next_bit_val)) - { - return maybe_neighbour_vals_of_crc (curr_bit_val, - as_a<bit_xor_expression *> - (next_bit_val)->get_left ()) - || maybe_neighbour_vals_of_crc (curr_bit_val, - as_a<bit_xor_expression *> - (next_bit_val)->get_right ()); - } - return false; -} - - -/* Returns true if in the CRC value's vector we have one of the form of - following consecutive bits - 1. crc[]^1 or crc[]^data[]^1, then crc[] - 2. crc[]^data[]^1, then crc[]^data[] - 3. crc[]^data[], then crc[] or data[] - 4. crc[]^data[], then crc[]^data[] - 5. crc[]^data[], then crc[]^data[]^1 - Otherwise returns false. */ -bool -maybe_neighbour_vals_of_crc (bit_xor_expression *curr_xor_exp, - value_bit *next_bit_val) -{ - if (!curr_xor_exp) - return true; - - /* The case when we have some_expression ^ 1 - for the current bit's value. */ - if (is_a<bit *> (curr_xor_exp->get_right ())) - { - /* The case when current bit's value is crc[]^1 or crc[]^data[]^1, - next bit's - crc[]. - There may not be ^ 0 case, as expressions are optimized. */ - if (is_a<symbolic_bit *> (next_bit_val)) - { - if (is_a<symbolic_bit *> (curr_xor_exp->get_left ())) - return maybe_neighbour_vals_of_crc (as_a<symbolic_bit *> - (curr_xor_exp->get_left ()), - next_bit_val); - if (is_a<bit_xor_expression *> (curr_xor_exp->get_left ())) - return maybe_neighbour_vals_of_crc (as_a<bit_xor_expression *> - (curr_xor_exp->get_left ()), - next_bit_val); - } - /* The case when current bit's value is crc[]^data[]^1, - next bit's - crc[]^data[]. */ - else if (is_a<bit_xor_expression *> (curr_xor_exp->get_left ()) - && is_a<bit_xor_expression *> (next_bit_val)) - return maybe_neighbour_vals_of_crc - (as_a<bit_xor_expression *> (curr_xor_exp->get_left ()), - next_bit_val); - else - return false; - } - /* The case when current bit's value is crc[]^data[]. */ - else if (is_a<symbolic_bit *> (curr_xor_exp->get_right ()) - && is_a<symbolic_bit *> (curr_xor_exp->get_left ())) - { - symbolic_bit * curr_xor_exp_left_sym - = as_a<symbolic_bit *> (curr_xor_exp->get_left ()); - symbolic_bit * curr_xor_exp_right_sym - = as_a<symbolic_bit *> (curr_xor_exp->get_right ()); - - /* The case when current bit's value is crc[]^data[], - next bit's - crc[] or data[]. */ - if (is_a<symbolic_bit *> (next_bit_val)) - { - return maybe_neighbour_vals_of_crc (curr_xor_exp_left_sym, - next_bit_val) - || maybe_neighbour_vals_of_crc (curr_xor_exp_right_sym, - next_bit_val); - } - /* The case when current bit's value is crc[]^data[], - next bit's - something ^ something. */ - else if (is_a<bit_xor_expression *> (next_bit_val)) - { - bit_xor_expression *curr_xor_exp = as_a<bit_xor_expression *> - (next_bit_val); - /* The case when current bit's value is crc[]^data[], - next bit's - crc[]^data[]. */ - if (is_a<symbolic_bit *> (curr_xor_exp->get_right ()) - && is_a<symbolic_bit *> (curr_xor_exp->get_left ())) - { - return - maybe_neighbour_vals_of_crc (curr_xor_exp_left_sym, - curr_xor_exp->get_left ()) - && maybe_neighbour_vals_of_crc (curr_xor_exp_right_sym, - curr_xor_exp->get_right ()); - } - /* The case when current bit's value is crc[]^data[], - next bit's - crc[]^data[]^1. */ - else if (is_a<bit *> (curr_xor_exp->get_right ()) - && is_a<bit_xor_expression *> (curr_xor_exp->get_left ())) - return maybe_neighbour_vals_of_crc (curr_xor_exp, - curr_xor_exp->get_left ()); - } - } - return false; -} - - -/* Returns true if crc_state matches the LFSR, otherwise - false. */ -bool -state_matches_lfsr (const value *lfsr, - const value *crc_state, - bool is_left_shift, state *final_state) -{ - bit * const_bit = nullptr; - symbolic_bit *symb_bit = nullptr; - value_bit *simple_xor_right = nullptr; - bit_xor_expression *xor_exp = nullptr, *complicated_xor = nullptr; - bool has_other_val = false; - - /* Depending on whether it is bit forward or reversed CRC, - determine significant bit, to examine that bit separately. */ - size_t it_beg = 0, sb_index = 0, - it_end = lfsr->length () < crc_state->length () - ? lfsr->length () : crc_state->length (); - if (is_left_shift) - { - sb_index = it_end-1; - it_beg = 1; - } - else - --it_end; - - /* Check what kind of values are in the returned state - (which is expected to be CRC). Return false, - if there is such a value which must exist in the CRC value. */ - for (unsigned j = it_beg; j < it_end - 1; ++j) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Checking %u bit's " - "and %u bit's compatibility.\n", j, j+1); - switch ((*crc_state)[j]->get_type ()) - { - case SYMBOLIC_BIT: - symb_bit = as_a<symbolic_bit *> ((*crc_state)[j]); - if (!maybe_neighbour_vals_of_crc (symb_bit, (*crc_state)[j+1])) - return false; - break; - case BIT: - const_bit = as_a<bit *> ((*crc_state)[j]); - if (!maybe_neighbour_vals_of_crc (const_bit, (*crc_state)[j+1])) - return false; - break; - case BIT_XOR_EXPRESSION: - { - /* Calculated CRC may contain crc[]^data[], - or crc[]^1, or crc[]^data[]^1. */ - xor_exp - = as_a<bit_xor_expression *> ((*crc_state)[j]); - - if (!maybe_neighbour_vals_of_crc (xor_exp, (*crc_state)[j+1])) - return false; - - if (is_a<symbolic_bit *> (xor_exp->get_left ()) - && (is_a<bit *> (xor_exp->get_right ()) - || is_a<symbolic_bit *> (xor_exp->get_right ()))) - simple_xor_right = xor_exp->get_right (); - else if (is_a<bit_xor_expression *> (xor_exp->get_left ()) - && is_a<bit *> (xor_exp->get_right ())) - { - complicated_xor = as_a<bit_xor_expression *> - (xor_exp->get_left ()); - simple_xor_right = xor_exp->get_right (); - } - else - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Not expected xor expression.\n"); - return false; - } - break; - } - default: - has_other_val = true; - } - } - - if (has_other_val) - return false; - - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Checks passed. Starting bit by bit matching.\n"); - - if (!const_bit && symb_bit && !complicated_xor - && (!simple_xor_right - || (simple_xor_right && is_a<bit *> (simple_xor_right)))) - return match_lfsr_case1 (lfsr, crc_state, symb_bit, is_left_shift, - it_beg, it_end, sb_index, final_state); - - if (!const_bit && !symb_bit) - return match_lfsr_case2 (lfsr, crc_state, xor_exp, is_left_shift, - it_beg, it_end, sb_index, final_state); - return false; -} - - -/* Returns true if all states match the LFSR, otherwise - false. */ -bool -crc_symb_execution::all_states_match_lfsr (value *lfsr, - bool is_left_shift) -{ - while (!final_states.is_empty ()) - { - state *final_state = final_states.last (); - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Matching LFSR and following returned state.\n"); - state::print_value (final_state->get_first_value ()); - final_state->print_conditions (); - } - if (!state_matches_lfsr (lfsr, final_state->get_first_value (), - is_left_shift, final_state)) - return false; - final_states.pop (); - delete final_state; - } - return true; -} diff --git a/gcc/symb-execute-all-paths.h b/gcc/symb-execute-all-paths.h deleted file mode 100644 index eedca27..0000000 --- a/gcc/symb-execute-all-paths.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - Execute symbolically all paths of the function. Iterate loops only once. - Copyright (C) 2006-2022 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#ifndef GCC_EXECUTE_ALL_PATHS_H -#define GCC_EXECUTE_ALL_PATHS_H - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "backend.h" -#include "tree.h" -#include "gimple.h" -#include "tree-pass.h" -#include "ssa.h" -#include "gimple-iterator.h" -#include "tree-cfg.h" -#include "tree-ssa-loop-niter.h" -#include "cfgloop.h" -#include "gimple-range.h" -#include "tree-scalar-evolution.h" -#include "hwint.h" -#include "function.h" -#include "sym-exec/state.h" - -class crc_symb_execution { - - private: - /* A vector of states to keep the current state of each executed path. */ - vec<state *> states; - - /* A vector of final states - to keep the returned_value and path conditions. */ - vec<state *> final_states; - -/* Assign symbolic values to the arguments of the function - and keep in the state. */ - static bool make_symbolic_func_args_and_sizes (function *, state *); - - /* Add declared ssa variables to the state. */ - static bool add_function_local_ssa_vars (function *, state *); - - bool execute_assign_statement (const gassign *); - - /* Add next basic blocks of the conditional block - for the execution path into the stack. */ - void add_next_bbs (basic_block, state *, auto_vec<edge, 20> &); - - /* Keep conditions depending on symbolic variables in the states. */ - static bool add_condition (const gcond *, state *, state *); - - /* Create new state for true and false branch. - Keep conditions in new created states. */ - bool resolve_condition (const gcond *, auto_vec<edge, 20> &); - - /* Keep the calculated value of the return value - and the conditions of the executed path. */ - bool keep_return_val_and_conditions (const greturn *); - - /* Execute gimple statements of the basic block. - Keeping values of variables in the state. */ - bool execute_bb_gimple_statements (basic_block, auto_vec<edge, 20> &); - - /* Assign values of phi instruction to its result. - Keep updated values in the state. */ - bool execute_bb_phi_statements (basic_block, edge); - - /* Execute all statements of the basic block. - Keeping values of variables in the state. */ - bool execute_bb_statements (basic_block, edge, auto_vec<edge, 20> &); - -/* Traverse function fun's all paths from the first basic block to the last. - Each time iterate loops only once. - Symbolically execute statements of each path. */ - bool traverse_function (function *); - - /* Execute the loop, which calculates crc with initial values, - to calculate the polynomial. */ - bool execute_crc_loop (class loop *, gphi *, gphi *, bool); - - public: - - /* Symbolically execute the function and keep final states. */ - bool execute_function (function *); - - /* Returns calculated polynomial by executing the loop - with concrete values. */ - value * extract_poly_and_create_lfsr (class loop *, gphi *, gphi *, bool); - - /* Returns true if all states match the LFSR, otherwise - false. */ - bool all_states_match_lfsr (value *, bool); - - crc_symb_execution () - { - /* Reserve memory for the vectors of states. */ - states.create (30); - final_states.create (30); - } - - ~crc_symb_execution () - { - /* Free memory. */ - states.release (); - final_states.release (); - } -}; - -#endif //GCC_EXECUTE_ALL_PATHS_H diff --git a/gcc/testsuite/gcc.dg/crc-25.c b/gcc/testsuite/gcc.dg/crc-25.c new file mode 100644 index 0000000..96add9e --- /dev/null +++ b/gcc/testsuite/gcc.dg/crc-25.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-crc-details" } */ + +#include <stdint.h> + +typedef uint8_t crc; +#define WIDTH (8 * sizeof(crc)) +#define TOPBIT (1 << (WIDTH - 1)) + +crc +crcSlow(uint8_t message) { + crc remainder = 0; + remainder ^= (message << (WIDTH - 8)); + for (uint8_t bit = 8; bit > 0; --bit) { + if (remainder & TOPBIT) { + remainder = (remainder << 1) ^ 1234; + } else { + remainder = (remainder << 1); + } + } + return (remainder); +} + +/* { dg-final { scan-tree-dump "crcSlow function maybe calculates CRC and returns it." "crc"} } */ +/* { dg-final { scan-tree-dump "Return size is 8" "crc"} } */ +/* { dg-final { scan-tree-dump "Loop iteration number is 7" "crc"} } */ +/* { dg-final { scan-tree-dump "Bit forward" "crc"} } */ +/* { dg-final { scan-tree-dump "Executing \[a-zA-Z_\]\[a-zA-Z0-9_\]* = \[a-zA-Z_\]\[a-zA-Z0-9_\]* \(<<|>>\) \[0-9]+;" "crc" } } */ +/* { dg-final { scan-tree-dump "crcSlow function calculates CRC." "crc"} } */
\ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/crc-callerid.c b/gcc/testsuite/gcc.dg/crc-callerid.c new file mode 100644 index 0000000..2d2dc74 --- /dev/null +++ b/gcc/testsuite/gcc.dg/crc-callerid.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-crc-details" } */ +unsigned short calc_crc(unsigned short crc, unsigned char data) +{ + unsigned int i, j, org, dst; + org = data; + dst = 0; + + for (i = 0; i < 8; i++) { + org <<= 1; + dst >>= 1; + if (org & 0x100) + dst |= 0x80; + } + data = (unsigned char) dst; + crc ^= (unsigned int) data << (16 - 8); + for (j = 0; j < 8; j++) { + if (crc & 0x8000U) + crc = (crc << 1) ^ 0x1021U ; + else + crc <<= 1 ; + } + return crc; +} +/* { dg-final { scan-tree-dump "calc_crc function maybe calculates CRC and returns it." "crc"} } */ +/* { dg-final { scan-tree-dump "Return size is 16" "crc"} } */ +/* { dg-final { scan-tree-dump "Loop iteration number is 7" "crc"} } */ +/* { dg-final { scan-tree-dump "Bit forward" "crc"} } */ +/* { dg-final { scan-tree-dump "calc_crc function calculates CRC." "crc"} } */
\ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/crc-cc1541.c b/gcc/testsuite/gcc.dg/crc-cc1541.c new file mode 100644 index 0000000..8a4ad4b --- /dev/null +++ b/gcc/testsuite/gcc.dg/crc-cc1541.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-crc-details" } */ +unsigned char +crc8(unsigned char value) +{ + for (int i = 0; i < 8; ++i) { + value = (value & 0x80) ? ((value << 1) ^ 0x31) : (value << 1); + } + + return value; +} +/* { dg-final { scan-tree-dump "crc8 function maybe calculates CRC and returns it." "crc"} } */ +/* { dg-final { scan-tree-dump "Return size is 8" "crc"} } */ +/* { dg-final { scan-tree-dump "Loop iteration number is 7" "crc"} } */ +/* { dg-final { scan-tree-dump "Bit forward" "crc"} } */ +/* { dg-final { scan-tree-dump "crc8 function calculates CRC." "crc"} } */
\ No newline at end of file |