From: Mariam Arutunian Date: Tue, 27 Dec 2022 14:52:46 +0000 (+0400) Subject: Refactored all files. Renamed gcc/symb-execute-all-paths.cc/h files to gcc/gcc/crc_ve... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fa7e023c6394d03add3449adc5033a7eb3fa250e;p=thirdparty%2Fgcc.git Refactored all files. Renamed gcc/symb-execute-all-paths.cc/h files to gcc/gcc/crc_verification.cc/h. Changes in Traverse and execute CRC function v8: - Delete states and final_states vectores more deeply. Changes in LFSR matching v4: - Added support of CRC mixed case matching. Changes in Testsuit: - Added checks of found CRC in crc-2,4,5,7,8 tests. - Changed CRC detection search messages. Changes in sym_exec v12: - Added clear_states function. --- diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 0365e599cfad..f69dab2da352 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1647,7 +1647,7 @@ OBJS = \ tree-iterator.o \ tree-logical-location.o \ tree-loop-distribution.o \ - symb-execute-all-paths.o \ + crc_verification.o \ gimple-crc-optimization.o \ sym-exec/expression.o \ sym-exec/state.o \ diff --git a/gcc/crc_verification.cc b/gcc/crc_verification.cc new file mode 100644 index 000000000000..c261a7510e0e --- /dev/null +++ b/gcc/crc_verification.cc @@ -0,0 +1,1501 @@ +/* + 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 +. */ + +#include "crc_verification.h" +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "tree.h" +#include "gimple.h" +#include "ssa.h" +#include "gimple-iterator.h" +#include "tree-cfg.h" +#include "cfganal.h" + + +/* This function assigns symbolic values to the arguments of the fun. + (Not complete). */ + +bool +crc_symbolic_execution::make_symbolic_func_args_and_sizes (function *fun, + state *initial_state) +{ + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "\nMaking symbolic the following arguments " + "of the function:\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_symbolic_execution::add_function_local_ssa_vars (function *fun, + state *initial_state) +{ + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "\n\nAdding the 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_symbolic_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 &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. + For example, if we have "for (int i=0; i<8; i++)", + i's value may not be 8 when we continue with the false branch. + But it's ok, as for checking CRC's value we don't need i's value. */ + 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_symbolic_execution::add_next_bbs (basic_block cond_bb, + state *new_branch_state, + auto_vec &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_symbolic_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) + + The condition is kept in the bit level. + For ex. + If a's size is 8 and its value is {symb_a, 0, 0, 0, 0, 0, 0, 0}, + then for a == 0 we'll have symb_a == 0 condition. + */ + + 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_symbolic_execution::resolve_condition (const gcond *cond, + auto_vec &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_symbolic_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_symbolic_execution::execute_bb_gimple_statements (basic_block bb, + auto_vec &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 (gs))) + return false; + break; + } + case GIMPLE_COND: + { + if (!resolve_condition (as_a (gs), stack)) + return false; + return true; + } + case GIMPLE_RETURN: + { + if (!keep_return_val_and_conditions (as_a (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_symbolic_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_symbolic_execution::execute_bb_statements (basic_block bb, + edge incoming_edge, + auto_vec &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_symbolic_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 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; +} + + +/* Symbolically execute function. */ + +bool +crc_symbolic_execution::execute (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; + 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_symbolic_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 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 ((*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_symbolic_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); +} + + +/**************************** LFSR MATCHING *********************************/ +// TODO write in separate file. + + +/* Returns true 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; +} + + +/* 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 (const_bit) + && (as_a (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 (bit)) + return false; + + size_t sym_bit_index = (as_a (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) + && is_a_valid_symb ((as_a (bit))->get_left (), + lfsr_bit_index) + && is_a_valid_symb ((as_a (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 must be + crc[8] or crc[16],... + + Otherwise, returns false. */ + +bool +is_a_valid_xor_one (value_bit *bit, size_t lfsr_bit_index) +{ + if (is_a (bit)) + { + value_bit *symb_exp = nullptr; + bit_xor_expression *xor_exp = as_a (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 the condition_exp and refernce_exp match. + This is done for finding the condition which checks MSB/LSB's value + (under which xor is/not done). */ + +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 (reference_exp)) + { + if (is_one (as_a (reference_exp)->get_right ())) + reference_exp = as_a + (reference_exp)->get_left (); + else if (is_a (condition_exp)) + return may_be_xors_condition (as_a + (reference_exp)->get_left (), + as_a + (condition_exp)->get_left (), + sb_index) + && may_be_xors_condition (as_a + (reference_exp)->get_right (), + as_a + (condition_exp)->get_right (), + sb_index); + return false; + } + if (is_a (reference_exp) + && is_a (condition_exp)) + { + symbolic_bit *condition_symbolic = as_a (condition_exp); + symbolic_bit *reference_symbolic = as_a (reference_exp); + return reference_symbolic->get_origin () + == condition_symbolic->get_origin () + && acceptable_diff (sb_index, + condition_symbolic->get_index ()); + } + if (is_a (reference_exp) + && is_a (condition_exp)) + return may_be_xors_condition (as_a (reference_exp), + as_a + (condition_exp)->get_left (), sb_index) + || may_be_xors_condition (as_a (reference_exp), + as_a + (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) + { + /* Get ordinal condition. */ + bit_condition *condition = nullptr; + if (is_a (*iter)) + condition = as_a (*iter); + else + continue; + + /* If the condition may be for checking MSB/LSB being 1/0, + then if is_one is 1 and condition is for checking MSB/LSB being one or + if is_one is 0 and condition is for checking MSB/LSB being 0 + return true, otherwise - false. */ + value_bit *cond_exp = (*iter)->get_left (); + if (may_be_xors_condition (symb_exp, cond_exp, sb_index)) + { + if (!is_a ((*iter)->get_right ())) + return false; + + unsigned char comparison_val = as_a ((*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; +} + + +/* Check whether LSB/MSB of LFSR and calculated (maybe)CRC match. + If LSB/MSB is checked for being one in the CRC code, + then here we check MSB/LSB. */ + +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 (lfsr)) + { + if (!((is_a (crc) + && as_a (crc)->get_val () + == as_a (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 (lfsr)) + { + if (!(is_a (crc) && ((as_a (crc)->get_val () == 0 + && check_condition (conditions_crc, 0, + sb_index, final_state)) + || (as_a (crc)->get_val () == 1 + && check_condition (conditions_crc, 1, + sb_index, + final_state))))) + return false; + return true; + } + return false; +} + + +/* Check whether significant bit 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 + symbolic_bits or symbolic_bits ^ 1, or + bit_xor_expression or bit_xor_expression ^ 1, + besides MSB/LSB (it may be constant). + + Under this are considered the cases, + when sizes of crc and data are same and + + 1. Data is xored with crc before the loop. + 2. Data is xored with crc in the loop. + 3. Data is xor-ed with crc only for checking the condition and + xor is done only on crc. */ + +bool +lfsr_and_crc_bits_match (const value *lfsr, + const value *crc_state, + value_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 ((*lfsr)[i])) + { + size_t index = (as_a ((*lfsr)[i]))->get_left () + ->get_index (); + if (!((is_a_valid_xor_one ((*crc_state)[i], index) + && check_condition ( + as_a ((*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)) + || (is_a_valid_xor ((*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 ((*lfsr)[i])) + { + size_t index = (as_a ((*lfsr)[i]))->get_index (); + if (!((is_a_valid_symb ((*crc_state)[i], index) + || 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; +} + + +/* 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 (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 (next_bit_val)) + return curr_bit_val->get_origin () + == as_a (next_bit_val)->get_origin (); + else if (is_a (next_bit_val)) + return maybe_neighbour_vals_of_crc (curr_bit_val, + as_a + (next_bit_val)->get_left ()) + || maybe_neighbour_vals_of_crc (curr_bit_val, + as_a + (next_bit_val)->get_right ()); + return false; +} + + +/* Check the case when current bit's value is crc[]^1 or crc[]^data[]^1. */ + +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 (next_bit_val)) + { + if (is_a (curr_xor_exp_left)) + return maybe_neighbour_vals_of_crc (as_a + (curr_xor_exp_left), + next_bit_val); + if (is_a (curr_xor_exp_left)) + return maybe_neighbour_vals_of_crc (as_a + (curr_xor_exp_left), + next_bit_val); + } + /* The case when current bit's value is crc[]^data[]^1, + next bit's - crc[]^data[]. */ + else if (is_a (curr_xor_exp_left) + && is_a (next_bit_val)) + return maybe_neighbour_vals_of_crc + (as_a (curr_xor_exp_left), + next_bit_val); + return false; +} + + +/* Check the case, when for the current bit we have crc[]^data[]. */ + +bool +check_xor_left_and_right_symb_case (bit_xor_expression *curr_xor_exp, + value_bit *next_bit_val) +{ + symbolic_bit *curr_xor_exp_left_sym + = as_a (curr_xor_exp->get_left ()); + symbolic_bit *curr_xor_exp_right_sym + = as_a (curr_xor_exp->get_right ()); + + /* The case when current bit's value is crc[]^data[], + next bit's - crc[] or data[]. */ + if (is_a (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 (next_bit_val)) + { + bit_xor_expression *next_bit_xor_exp = as_a + (next_bit_val); + /* The case when current bit's value is crc[]^data[], + next bit's - crc[]^data[]. */ + if (is_a (next_bit_xor_exp->get_right ()) + && is_a (next_bit_xor_exp->get_left ())) + return + maybe_neighbour_vals_of_crc (curr_xor_exp_left_sym, + next_bit_xor_exp->get_left ()) + && maybe_neighbour_vals_of_crc (curr_xor_exp_right_sym, + next_bit_xor_exp->get_right ()); + /* The case when current bit's value is crc[]^data[], + next bit's - crc[]^data[]^1. */ + else if (is_a (next_bit_xor_exp->get_right ()) + && is_a (next_bit_xor_exp->get_left ())) + return maybe_neighbour_vals_of_crc (curr_xor_exp, + next_bit_xor_exp->get_left ()); + } + 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 (curr_xor_exp->get_right ())) + return check_xor_right_1_case (curr_xor_exp->get_left (), next_bit_val); + /* The case when current bit's value is crc[]^data[]. */ + else if (is_a (curr_xor_exp->get_right ()) + && is_a (curr_xor_exp->get_left ())) + return check_xor_left_and_right_symb_case (curr_xor_exp, next_bit_val); + return false; +} + + +/* Checks that crc_state's all bit values may be real CRC's values. + 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) +{ + /* Depending on whether it is bit forward or reversed CRC, + determine in which significant bit new value is added, + to examine that bit separately. + If in the CRC alg MSB (sb_index) is checked to be one for xor, + then here we check LSB separately (marginal bit). + If LSB (sb_index) is checked, then we separate MSB (marginal bit). */ + 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; + + symbolic_bit *symb_bit = nullptr; + bit_xor_expression *xor_exp = nullptr; + + /* Check what kind of values are in the returned crc_state + (which is expected to be CRC), except for marginal bit. Return false, + if there is such a value which must not 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 ((*crc_state)[j]); + if (!maybe_neighbour_vals_of_crc (symb_bit, (*crc_state)[j + 1])) + return false; + break; + } + case BIT: + /* Except for marginal bit there mustn't be other constants. + (For some implementations we get constant values for CRC, + but we don't support those cases). */ + return false; + case BIT_XOR_EXPRESSION: + { + /* Calculated CRC may contain crc[]^data[], + or crc[]^1, or crc[]^data[]^1. */ + xor_exp = as_a ((*crc_state)[j]); + if (!maybe_neighbour_vals_of_crc (xor_exp, (*crc_state)[j + 1])) + return false; + break; + } + default: + /* There may not be other type of bit values in the CRC. */ + return false; + } + } + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Checks passed. Starting bit by bit matching.\n"); + + /* Determine which value might have been checked in the condition. */ + value_bit *reference_val = nullptr; + if (symb_bit) + reference_val = symb_bit; + else if (!symb_bit) + reference_val = xor_exp; + + /* Check whether crc_state and lfsr bits match. */ + return lfsr_and_crc_bits_match (lfsr, crc_state, reference_val, is_left_shift, + it_beg, it_end, sb_index, final_state); + return false; +} + + +/* Returns true if all states from final_states match the LFSR, + otherwise - false. */ + +bool +all_states_match_lfsr (value *lfsr, + bool is_left_shift, + const vec &final_states) +{ + for (size_t i=0; i < final_states.length (); ++i) + { + state *final_state = final_states[i]; + 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; + } + return true; +} diff --git a/gcc/crc_verification.h b/gcc/crc_verification.h new file mode 100644 index 000000000000..59f76298230b --- /dev/null +++ b/gcc/crc_verification.h @@ -0,0 +1,168 @@ +/* + Execute symbolically all paths of the function, iterating loops only once. + Calculate the value of the polynomial by executing loop with real values. + Check calculated final states of return values match determined LFSR. + 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 +. */ + +#ifndef GCC_CRC_VERIFICATION +#define GCC_CRC_VERIFICATION + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "cfgloop.h" +#include "sym-exec/state.h" + +class crc_symbolic_execution { + + private: + /* A vector of states to keep the current state of each executed path. */ + vec states; + + /* A vector of final states + to keep the returned_value and path conditions. */ + vec 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 &); + + /* 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 &); + + /* 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 &); + + /* 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 &); + +/* 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 *); + + /* Returns calculated polynomial by executing the loop + with concrete values. */ + value *extract_poly_and_create_lfsr (class loop *, gphi *, gphi *, bool); + + const vec &get_final_states () + { + return final_states; + } + + crc_symbolic_execution () + { + /* Reserve memory for the vectors of states. */ + states.create (30); + final_states.create (30); + } + + ~crc_symbolic_execution () + { + /* Free memory. */ + state::clear_states (&states); + state::clear_states (&final_states); + } +}; + + +/**************************** LFSR MATCHING *********************************/ +// TODO write in separate file + +/* Returns true if all states match the LFSR, otherwise - false. */ +bool +all_states_match_lfsr (value *, + bool, + const vec &); + + +/* 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 *, value_bit *); + + +/* 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 *, value_bit *); + + +/* 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 *, + value_bit *); + + +#endif //GCC_CRC_VERIFICATION diff --git a/gcc/gimple-crc-optimization.cc b/gcc/gimple-crc-optimization.cc index 44cf08ebc704..a792769f347e 100644 --- a/gcc/gimple-crc-optimization.cc +++ b/gcc/gimple-crc-optimization.cc @@ -34,7 +34,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple-range.h" #include "tree-scalar-evolution.h" #include "hwint.h" -#include "symb-execute-all-paths.h" +#include "crc_verification.h" class crc_optimization { private: @@ -56,7 +56,7 @@ class crc_optimization { gphi *second_phi_for_crc; /* Phi statement, result maybe data (if exists). */ - gphi * data; + gphi *data; /* The loop, which probably calculates CRC. */ class loop *crc_loop; @@ -66,7 +66,10 @@ class crc_optimization { /* Function's return value size. */ unsigned HOST_WIDE_INT return_size; - /* Depending on the value, may be forward or reversed CRC. */ + /* Depending on the value of is_left_shift, + may be forward or reversed CRC. + If is_left_shift, then it is bit_forward implementations, + otherwise bit_reversed. */ bool is_left_shift; /* Will be true, if crc variable and if condition depend on each other. */ @@ -76,7 +79,6 @@ class crc_optimization { otherwise it may calculate CRC. */ bool clean_xor_maybe_crc; - void set_initial_values () { shift_before_xor = nullptr; @@ -99,12 +101,12 @@ class crc_optimization { /* Checks the loop iteration number. The loop for CRC calculation may do 8, 16, 24, 32 iterations. */ - bool is_loop_of_crc_calculation (class loop *func_loop); + bool maybe_crc_iteration_count (class loop *func_loop); /* Check whether found xor_stmt is for calculating crc. - The function fun calculates crc only if there is a shift operation + The function crc_fun calculates crc only if there is a shift operation in the crc_loop. */ - bool xor_calculates_crc (function *fun, class loop *crc_loop, + bool xor_calculates_crc (function *crc_fun, class loop *crc_loop, const gimple *stmt); /* This function goes up through the def-chain of the name, @@ -115,7 +117,7 @@ class crc_optimization { or check_def_stmt_for_if function. */ void get_dep (tree name, - bool (crc_optimization::*continue_to_check_dep) (gimple* stmt)); + bool (crc_optimization::*continue_to_check_dep) (gimple *stmt)); /* Checks whether the def_stmt statement, dependent from xor's operands, does shift operation for calculating crc @@ -123,20 +125,20 @@ class crc_optimization { Returns false, if there is an instruction which may not exist in the CRC loop. Returns true, if the def-chain examination must be continued. */ - bool continue_to_check_dep_for_xor (gimple* stmt); + bool continue_to_check_dep_for_xor (gimple *stmt); /* Checks whether if's condition and xor-ed variable are dependent from the same variable. (The crc variable is xor-ed if variable's MSB/LSB is 1). Also determines phi instruction's of data and crc (for further polynomial extraction). */ - bool continue_to_check_dep_for_if (gimple* stmt); + bool continue_to_check_dep_for_if (gimple *stmt); /* This function checks that xor is done under the condition of MSB/LSB being one. Checks that if condition's variable and xor-ed variable - depend on same variable and if there is a shift1 in the same block with xor, - on the opposite branch must be another shift1 to the same direction. + depend on same variable and if there is a shift 1 in the same block with xor, + on the opposite branch must be another shift 1 to the same direction. xor_bb is the basic block, where xor operation is done. pred_bb is the predecessor basic block of the xor_bb, it is assumed that the last stmt of pred_bb checks the condition @@ -168,7 +170,7 @@ class crc_optimization { /* Get the return value size of the function and assign to return_size member. */ - void set_return_value_size (function *fun); + void set_return_value_size (function *crc_fun); /* This function checks whether calculated crc value (maybe modified) is returned. @@ -184,7 +186,9 @@ class crc_optimization { }; -/* Set GIMPLE_PHI and GIMPLE statements of the crc loop not visited. */ +/* TODO use existing code or move the function. + Set GIMPLE_PHI and GIMPLE statements of the crc loop not visited. */ + void set_loop_statements_not_visited (class loop *loop) { @@ -210,7 +214,10 @@ set_loop_statements_not_visited (class loop *loop) } } -/* Set GIMPLE_PHI and GIMPLE statements of the function not visited. */ + +/* TODO use existing code or move the function. + Set GIMPLE_PHI and GIMPLE statements of the function not visited. */ + static void set_all_statements_not_visited (function *fun) { @@ -234,6 +241,7 @@ set_all_statements_not_visited (function *fun) /* Prints extracted details of CRC calculation. */ + void crc_optimization::print_crc_information () { @@ -293,10 +301,10 @@ crc_optimization::returned_value_depends_on_crc (tree lhs) and assign to return_size member. */ void -crc_optimization::set_return_value_size (function *fun) +crc_optimization::set_return_value_size (function *crc_fun) { return_size = 0; - tree tree_return_value_size = DECL_SIZE (DECL_RESULT (fun->decl)); + tree tree_return_value_size = DECL_SIZE (DECL_RESULT (crc_fun->decl)); if (tree_fits_uhwi_p (tree_return_value_size)) { return_size = tree_to_uhwi (tree_return_value_size); @@ -343,12 +351,12 @@ crc_optimization::find_shift_after_xor (class loop *crc_loop, tree lhs) find_shift_after_xor (crc_loop, gimple_phi_result (stmt)); } - else if (is_gimple_assign (stmt)) - if (can_not_be_shift_of_crc (stmt, false)) - { - shift_after_xor = nullptr; - return; - } + else if (is_gimple_assign (stmt) + && can_not_be_shift_of_crc (stmt, false)) + { + shift_after_xor = nullptr; + return; + } } } @@ -431,6 +439,9 @@ crc_optimization::crc_cond_and_shift (const basic_block &pred_bb, const basic_block &xor_bb) { gcond *cond = nullptr; + /* Check whether pred_bb contains condition. + We will consider only those cases + when xor is done immediately under condition. */ if (is_a (last_stmt (pred_bb))) cond = as_a (last_stmt (pred_bb)); if (!cond) @@ -509,6 +520,7 @@ crc_optimization::is_acceptable_statement (const tree_code &stmt_code) || TREE_CODE_CLASS (stmt_code) == tcc_unary; } + /* Checks whether assigment statement does shift operation (checks that shift 1 is done), if it doesn't - checks whether it is acceptable operation @@ -547,7 +559,7 @@ crc_optimization::can_not_be_shift_of_crc (gimple *assign_stmt, shift_after_xor = assign_stmt; if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, - "Found shift1 after xor.\n"); + "Found <<1 or >>1 after xor.\n"); } return false; } @@ -567,9 +579,9 @@ crc_optimization::can_not_be_shift_of_crc (gimple *assign_stmt, { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, - "\nStmt with following operation " + "\nStmt with the following operation " "code %s between xor and shift, " - "may not be crc.\n", get_tree_code_name (stmt_code)); + "may not be CRC.\n", get_tree_code_name (stmt_code)); return true; } @@ -587,7 +599,7 @@ crc_optimization::can_not_be_shift_of_crc (gimple *assign_stmt, void crc_optimization::get_dep (tree name, bool (crc_optimization::*continue_to_check_dep) ( - gimple* ssa)) + gimple *ssa)) { if (!(name && TREE_CODE (name) == SSA_NAME)) return; @@ -622,7 +634,7 @@ crc_optimization::get_dep (tree name, get_dep (ssa1, continue_to_check_dep); get_dep (ssa2, continue_to_check_dep); } - else if (is_a (stmt) && !bb_loop_header_p (gimple_bb (stmt))) + else if (is_a (stmt) && !bb_loop_header_p (gimple_bb (stmt))) { for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++) { @@ -668,13 +680,13 @@ crc_optimization::continue_to_check_dep_for_xor (gimple *def_stmt) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, - "Phi's definition is in loop header.\n"); + "Phi's definition is in the loop header.\n"); /* The case when polynomial's value is determined by a phi statement. */ if (first_phi_for_crc) { - second_phi_for_crc = as_a (def_stmt); + second_phi_for_crc = as_a (def_stmt); if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Set second phi.\n"); } @@ -682,12 +694,12 @@ crc_optimization::continue_to_check_dep_for_xor (gimple *def_stmt) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Set first phi.\n"); - first_phi_for_crc = as_a (def_stmt); + first_phi_for_crc = as_a (def_stmt); } return true; } } - return true; + return true; } @@ -723,7 +735,7 @@ crc_optimization::continue_to_check_dep_for_if (gimple *def_stmt) if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, - "If condition has dependence " + "The condition of if statement has dependence " "from the same variable as xor.\n" "CRC's phi statement is:\n"); print_gimple_stmt (dump_file, def_stmt, dump_flags); @@ -743,7 +755,7 @@ crc_optimization::continue_to_check_dep_for_if (gimple *def_stmt) return false; } - data = as_a (def_stmt); + data = as_a (def_stmt); if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, @@ -757,11 +769,11 @@ crc_optimization::continue_to_check_dep_for_if (gimple *def_stmt) /* Check whether found xor_stmt is for calculating crc. - The function fun calculates crc only if there is a shift operation + The function crc_fun calculates crc only if there is a shift operation in the crc_loop. */ bool -crc_optimization::xor_calculates_crc (function *fun, class loop *crc_loop, +crc_optimization::xor_calculates_crc (function *crc_fun, class loop *crc_loop, const gimple *xor_stmt) { tree crc_var = gimple_assign_lhs (xor_stmt); @@ -770,11 +782,10 @@ crc_optimization::xor_calculates_crc (function *fun, class loop *crc_loop, get_dep (crc_var, &crc_optimization::continue_to_check_dep_for_xor); - if (!clean_xor_maybe_crc) { if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Xor doesn't calculate crc.\n"); + fprintf (dump_file, "Xor isn't used for CRC calculation.\n"); return false; } @@ -803,21 +814,22 @@ crc_optimization::xor_calculates_crc (function *fun, class loop *crc_loop, { if (crc_cond_and_shift (single_pred (bb), bb)) { - set_all_statements_not_visited (fun); + set_all_statements_not_visited (crc_fun); bool crc_is_returned = returned_value_depends_on_crc (crc_var); if (dump_file) { if (crc_is_returned) { fprintf (dump_file, - "\nAttention! %s function calculates CRC.\n", - function_name (fun)); + "\n%s function maybe calculates CRC " + "and returns it.\n", + function_name (crc_fun)); } else { fprintf (dump_file, - "\nFound naive crc implementation in %s.\n", - function_name (fun)); + "\n%s function maybe calculates CRC.\n", + function_name (crc_fun)); } } return true; @@ -837,7 +849,7 @@ crc_optimization::xor_calculates_crc (function *fun, class loop *crc_loop, The loop for CRC calculation may do 8, 16, 24, 32 iterations. */ bool -crc_optimization::is_loop_of_crc_calculation (class loop *func_loop) +crc_optimization::maybe_crc_iteration_count (class loop *func_loop) { loop_iteration_number = 0; tree n_inters = number_of_latch_executions (func_loop); @@ -846,6 +858,7 @@ crc_optimization::is_loop_of_crc_calculation (class loop *func_loop) if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Loop iteration number is chrec_dont_know.\n"); + return false; } else if (tree_fits_uhwi_p (n_inters)) @@ -856,7 +869,8 @@ crc_optimization::is_loop_of_crc_calculation (class loop *func_loop) loop_iteration_number); if (!(loop_iteration_number == 7 || loop_iteration_number == 15 - || loop_iteration_number == 23 || loop_iteration_number == 31)) + || loop_iteration_number == 23 || loop_iteration_number == 31 + || loop_iteration_number == 63)) return false; } return true; @@ -888,7 +902,7 @@ crc_optimization::function_may_calculate_crc (function *fun) if (!loop || loop->inner) continue; - if (!is_loop_of_crc_calculation (loop)) + if (!maybe_crc_iteration_count (loop)) continue; crc_loop = loop; @@ -925,55 +939,53 @@ crc_optimization::function_may_calculate_crc (function *fun) return false; } + unsigned int crc_optimization::execute (function *fun) { if (function_may_calculate_crc (fun)) - { - crc_symb_execution symb_exec; - if (!symb_exec.execute_function (fun)) - { - if (dump_file) - fprintf (dump_file, "\nAttention! Not the CRC we want!\n"); - return 0; - } - - crc_symb_execution execute_loop; - value * lfsr - = execute_loop.extract_poly_and_create_lfsr (crc_loop, first_phi_for_crc, - data, is_left_shift); + { + crc_symbolic_execution symbolically_execute_function; + if (!symbolically_execute_function.execute (fun)) + { + if (dump_file) + fprintf (dump_file, "\nCRC verification didn't succeed " + "during symbolic execution!\n"); + return 0; + } + crc_symbolic_execution execute_loop; + value *lfsr + = execute_loop.extract_poly_and_create_lfsr (crc_loop, + first_phi_for_crc, + data, is_left_shift); if (!lfsr) { - if (dump_file) - fprintf (dump_file, "Couldn't create LFSR!\n"); - return 0; + if (dump_file) + fprintf (dump_file, "Couldn't create LFSR!\n"); + return 0; } - else + + if (dump_file && (dump_flags & TDF_DETAILS)) { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "\nLFSR value is \n"); - state::print_value (lfsr); - } + fprintf (dump_file, "\nLFSR value is \n"); + state::print_value (lfsr); } - if (symb_exec.all_states_match_lfsr (lfsr, is_left_shift)) + if (all_states_match_lfsr (lfsr, is_left_shift, + symbolically_execute_function + .get_final_states ())) { if (dump_file) - { - fprintf (dump_file, "The function really calculates CRC " - "and returns it!\n"); - } + fprintf (dump_file, "%s function calculates CRC!\n", + function_name (fun)); } else { if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Returned state and LFSR differ.\n"); - } + fprintf (dump_file, "Returned state and LFSR differ.\n"); } - } + } return 0; } diff --git a/gcc/sym-exec/state.cc b/gcc/sym-exec/state.cc index 95e6bd42686b..f2aae1d619ff 100644 --- a/gcc/sym-exec/state.cc +++ b/gcc/sym-exec/state.cc @@ -26,7 +26,7 @@ state::state (const state &s) state::~state () { - clear_states (); + clear_var_states (); clear_conditions (); } @@ -164,7 +164,19 @@ state::bulk_add_conditions (const hash_set &conds) void -state::clear_states () +state::clear_states (vec *states) +{ + while (!states->is_empty ()) + { + delete states->last (); + states->pop (); + } + states->release (); +} + + +void +state::clear_var_states () { for (auto iter = var_states.begin (); iter != var_states.end (); ++iter) { diff --git a/gcc/sym-exec/state.h b/gcc/sym-exec/state.h index b8311cdb2fcc..67913e9f934e 100644 --- a/gcc/sym-exec/state.h +++ b/gcc/sym-exec/state.h @@ -226,7 +226,9 @@ class state { bool add_var_state (tree var, value *state); - void clear_states (); + static void clear_states (vec *states); + + void clear_var_states (); void clear_conditions (); diff --git a/gcc/testsuite/gcc.dg/crc-1.c b/gcc/testsuite/gcc.dg/crc-1.c index d65763b2b2a8..cfa78e049b11 100644 --- a/gcc/testsuite/gcc.dg/crc-1.c +++ b/gcc/testsuite/gcc.dg/crc-1.c @@ -48,7 +48,7 @@ uint16_t gen_crc16(const uint8_t *data, uint16_t size) { return crc; } -/* { dg-final { scan-tree-dump "Found naive crc implementation in gen_crc16." "crc"} } */ +/* { dg-final { scan-tree-dump "gen_crc16 function maybe calculates CRC." "crc"} } */ /* { dg-final { scan-tree-dump "Return size is 16" "crc"} } */ /* { dg-final { scan-tree-dump "Loop iteration number is 15" "crc"} } */ /* { dg-final { scan-tree-dump "Bit forward" "crc"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-10.c b/gcc/testsuite/gcc.dg/crc-10.c index 29ee5686e42c..7cf77b856d6b 100644 --- a/gcc/testsuite/gcc.dg/crc-10.c +++ b/gcc/testsuite/gcc.dg/crc-10.c @@ -17,7 +17,7 @@ u8 crc8(u16 data) { return (u8)(data >> 8); } -/* { dg-final { scan-tree-dump "Attention! crc8 function calculates CRC." "crc"} } */ +/* { 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"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-11.c b/gcc/testsuite/gcc.dg/crc-11.c index 89d12f866766..8f11345dc956 100644 --- a/gcc/testsuite/gcc.dg/crc-11.c +++ b/gcc/testsuite/gcc.dg/crc-11.c @@ -23,5 +23,5 @@ ee_u16 not_crcu8(ee_u8 data, ee_u16 crc) { } return crc; } -/* { dg-final { scan-tree-dump-times "Attention! crcu8 function calculates CRC." 0 "crc"} } */ +/* { dg-final { scan-tree-dump-times "crcu8 function maybe calculates CRC" 0 "crc"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-12.c b/gcc/testsuite/gcc.dg/crc-12.c index 66c6743b62a5..09de56b53ab4 100644 --- a/gcc/testsuite/gcc.dg/crc-12.c +++ b/gcc/testsuite/gcc.dg/crc-12.c @@ -23,5 +23,5 @@ notCrc(uint8_t const message[], int nBytes) { return (remainder); } -/* { dg-final { scan-tree-dump-times "Attention! notCrc function calculates CRC." 0 "crc"} } */ +/* { dg-final { scan-tree-dump-times "notCrc function maybe calculates CRC" 0 "crc"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-13.c b/gcc/testsuite/gcc.dg/crc-13.c index ee4edde225f8..0c7fce66dc21 100644 --- a/gcc/testsuite/gcc.dg/crc-13.c +++ b/gcc/testsuite/gcc.dg/crc-13.c @@ -17,5 +17,5 @@ uint16_t not_crc16_update(uint16_t crc, uint8_t a) { return crc; } -/* { dg-final { scan-tree-dump-times "Attention! not_crc16_update function calculates CRC." 0 "crc"} } */ +/* { dg-final { scan-tree-dump-times "not_crc16_update function maybe calculates CRC" 0 "crc"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-14.c b/gcc/testsuite/gcc.dg/crc-14.c index ab1cf04c9823..7dd23995abf6 100644 --- a/gcc/testsuite/gcc.dg/crc-14.c +++ b/gcc/testsuite/gcc.dg/crc-14.c @@ -14,5 +14,5 @@ uint16_t not_crc(uint16_t crc, uint8_t a) { return crc; } -/* { dg-final { scan-tree-dump-times "Attention! not_crc function calculates CRC." 0 "crc"} } */ +/* { dg-final { scan-tree-dump-times "not_crc function maybe calculates CRC" 0 "crc"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-15.c b/gcc/testsuite/gcc.dg/crc-15.c index a9f8c84e0ba7..742922884dc3 100644 --- a/gcc/testsuite/gcc.dg/crc-15.c +++ b/gcc/testsuite/gcc.dg/crc-15.c @@ -21,6 +21,6 @@ uint8_t not_crc(uint8_t *data, size_t len) { return crc; } -/* { dg-final { scan-tree-dump-times "Attention! not_crc function calculates CRC." 0 "crc"} } */ +/* { dg-final { scan-tree-dump-times "not_crc function maybe calculates CRC" 0 "crc"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-16.c b/gcc/testsuite/gcc.dg/crc-16.c index 4e0983acfd3f..5e1a166550f6 100644 --- a/gcc/testsuite/gcc.dg/crc-16.c +++ b/gcc/testsuite/gcc.dg/crc-16.c @@ -18,6 +18,6 @@ u8 not_crc(u16 data) { return (u8)(data >> 8); } -/* { dg-final { scan-tree-dump-times "Attention! not_crc function calculates CRC." 0 "crc"} } */ +/* { dg-final { scan-tree-dump-times "not_crc function maybe calculates CRC" 0 "crc"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-17.c b/gcc/testsuite/gcc.dg/crc-17.c index 9f04c0498b7c..fd439a798ffe 100644 --- a/gcc/testsuite/gcc.dg/crc-17.c +++ b/gcc/testsuite/gcc.dg/crc-17.c @@ -15,5 +15,5 @@ uint16_t not_crc(uint16_t crc, uint8_t a) { return crc; } -/* { dg-final { scan-tree-dump-times "Attention! not_crc function calculates CRC." 0 "crc"} } */ +/* { dg-final { scan-tree-dump-times "not_crc function maybe calculates CRC" 0 "crc"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-18.c b/gcc/testsuite/gcc.dg/crc-18.c index b023fc21fa5a..c3cf813fb786 100644 --- a/gcc/testsuite/gcc.dg/crc-18.c +++ b/gcc/testsuite/gcc.dg/crc-18.c @@ -16,5 +16,5 @@ int16_t not_crc(int16_t crc, int8_t a) { return crc; } -/* { dg-final { scan-tree-dump-times "Attention! not_crc function calculates CRC." 0 "crc"} } */ +/* { dg-final { scan-tree-dump-times "not_crc function maybe calculates CRC" 0 "crc"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-19.c b/gcc/testsuite/gcc.dg/crc-19.c index eea073de9243..a25fb278654c 100644 --- a/gcc/testsuite/gcc.dg/crc-19.c +++ b/gcc/testsuite/gcc.dg/crc-19.c @@ -12,5 +12,5 @@ uint16_t not_crc(uint16_t crc, uint8_t a) { return crc; } -/* { dg-final { scan-tree-dump-times "Attention! not_crc function calculates CRC." 0 "crc"} } */ +/* { dg-final { scan-tree-dump-times "not_crc function maybe calculates CRC" 0 "crc"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-2.c b/gcc/testsuite/gcc.dg/crc-2.c index e1d342d09d1b..55d03bdd3ecc 100644 --- a/gcc/testsuite/gcc.dg/crc-2.c +++ b/gcc/testsuite/gcc.dg/crc-2.c @@ -21,9 +21,10 @@ unsigned int crc16(unsigned int crcValue, unsigned char newByte) { return crcValue; } -/* { dg-final { scan-tree-dump "Attention! crc16 function calculates CRC." "crc"} } */ +/* { dg-final { scan-tree-dump "crc16 function maybe calculates CRC and returns it." "crc"} } */ /* { dg-final { scan-tree-dump "Return size is 32" "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_\]* \\\^ \[a-zA-Z0-9_\]+\(\\\(\[a-zA-Z\]\\\)\)?;" "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 "crc16 function calculates CRC!" "crc"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-20.c b/gcc/testsuite/gcc.dg/crc-20.c index e9b68976b80b..82e1b53541e9 100644 --- a/gcc/testsuite/gcc.dg/crc-20.c +++ b/gcc/testsuite/gcc.dg/crc-20.c @@ -18,5 +18,5 @@ uint16_t not_crc(uint16_t crc, uint8_t a) { return crc; } -/* { dg-final { scan-tree-dump-times "Attention! not_crc function calculates CRC." 0 "crc"} } */ +/* { dg-final { scan-tree-dump-times "not_crc function maybe calculates CRC" 0 "crc"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-21.c b/gcc/testsuite/gcc.dg/crc-21.c index c54920af3fac..c7b496273c9c 100644 --- a/gcc/testsuite/gcc.dg/crc-21.c +++ b/gcc/testsuite/gcc.dg/crc-21.c @@ -22,4 +22,4 @@ ee_u16 not_crc(ee_u8 data, ee_u16 crc) { return crc; } -/* { dg-final { scan-tree-dump-times "Attention! not_crc function calculates CRC." 0 "crc"} } */ \ No newline at end of file +/* { dg-final { scan-tree-dump-times "not_crc function maybe calculates CRC" 0 "crc"} } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/crc-22.c b/gcc/testsuite/gcc.dg/crc-22.c index 153eb6b31406..80a9ebab1162 100644 --- a/gcc/testsuite/gcc.dg/crc-22.c +++ b/gcc/testsuite/gcc.dg/crc-22.c @@ -14,4 +14,4 @@ uint8_t not_crc(uint8_t crc, uint8_t data) { } return crc; } -/* { dg-final { scan-tree-dump-times "Attention! not_crc function calculates CRC." 0 "crc"} } */ +/* { dg-final { scan-tree-dump-times "not_crc function maybe calculates CRC" 0 "crc"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-23.c b/gcc/testsuite/gcc.dg/crc-23.c index a0d1d9c4c273..afc12827b732 100644 --- a/gcc/testsuite/gcc.dg/crc-23.c +++ b/gcc/testsuite/gcc.dg/crc-23.c @@ -15,7 +15,7 @@ uint16_t crc16(uint16_t crc, uint8_t a, uint16_t polynom) { return crc; } -/* { dg-final { scan-tree-dump "Attention! crc16 function calculates CRC." "crc"} } */ +/* { dg-final { scan-tree-dump "crc16 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 reversed" "crc"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-24.c b/gcc/testsuite/gcc.dg/crc-24.c index ee015da54002..6eee036fd578 100644 --- a/gcc/testsuite/gcc.dg/crc-24.c +++ b/gcc/testsuite/gcc.dg/crc-24.c @@ -51,7 +51,7 @@ uint16_t gen_crc16(const uint8_t *data, uint16_t size) { return crc; } -/* { dg-final { scan-tree-dump "Found naive crc implementation in gen_crc16." "crc"} } */ +/* { dg-final { scan-tree-dump "gen_crc16 function maybe calculates CRC." "crc"} } */ /* { dg-final { scan-tree-dump "Return size is 16" "crc"} } */ /* { dg-final { scan-tree-dump "Loop iteration number is 15" "crc"} } */ /* { dg-final { scan-tree-dump "Bit forward" "crc"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-3.c b/gcc/testsuite/gcc.dg/crc-3.c index 0186d36bb5da..cf5267c46424 100644 --- a/gcc/testsuite/gcc.dg/crc-3.c +++ b/gcc/testsuite/gcc.dg/crc-3.c @@ -26,7 +26,7 @@ unsigned short crc16(char *data_p, unsigned short length) { return (crc); } -/* { dg-final { scan-tree-dump "Attention! crc16 function calculates CRC." "crc"} } */ +/* { dg-final { scan-tree-dump "crc16 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 reversed" "crc"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-4.c b/gcc/testsuite/gcc.dg/crc-4.c index 7cc18f77102d..7cd3d62ea154 100644 --- a/gcc/testsuite/gcc.dg/crc-4.c +++ b/gcc/testsuite/gcc.dg/crc-4.c @@ -15,9 +15,10 @@ uint16_t crc16_update(uint16_t crc, uint8_t a) { return crc; } -/* { dg-final { scan-tree-dump "Attention! crc16_update function calculates CRC." "crc"} } */ +/* { dg-final { scan-tree-dump "crc16_update 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 reversed" "crc"} } */ /* { dg-final { scan-tree-dump "Executing \[a-zA-Z_\]\[a-zA-Z0-9_\]* = \[a-zA-Z_\]\[a-zA-Z0-9_\]* \\\^ \[a-zA-Z0-9_\]+\(\\\(\[a-zA-Z\]\\\)\)?;" "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 "crc16_update function calculates CRC!" "crc"} } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/crc-5.c b/gcc/testsuite/gcc.dg/crc-5.c index 257e70b51823..c9009051b3e2 100644 --- a/gcc/testsuite/gcc.dg/crc-5.c +++ b/gcc/testsuite/gcc.dg/crc-5.c @@ -22,9 +22,10 @@ ee_u16 crcu8(ee_u8 data, ee_u16 crc) { } return crc; } -/* { dg-final { scan-tree-dump "Attention! crcu8 function calculates CRC." "crc"} } */ +/* { dg-final { scan-tree-dump "crcu8 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 reversed" "crc"} } */ /* { dg-final { scan-tree-dump "Executing \[a-zA-Z_\]\[a-zA-Z0-9_\]* = \[a-zA-Z_\]\[a-zA-Z0-9_\]* \\\^ \[a-zA-Z0-9_\]+\(\\\(\[a-zA-Z\]\\\)\)?;" "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 "crcu8 function calculates CRC!" "crc"} } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/crc-6.c b/gcc/testsuite/gcc.dg/crc-6.c index 9802ab35b02e..cfb40b47b271 100644 --- a/gcc/testsuite/gcc.dg/crc-6.c +++ b/gcc/testsuite/gcc.dg/crc-6.c @@ -26,7 +26,7 @@ crcSlow(uint8_t const message[], int nBytes) { return (remainder); } -/* { dg-final { scan-tree-dump "Attention! crcSlow function calculates CRC." "crc"} } */ +/* { 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"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-7.c b/gcc/testsuite/gcc.dg/crc-7.c index f05d0557f097..d042a0b7b876 100644 --- a/gcc/testsuite/gcc.dg/crc-7.c +++ b/gcc/testsuite/gcc.dg/crc-7.c @@ -15,9 +15,10 @@ uint16_t crc_xmodem_update(uint16_t crc, uint8_t data) { return crc; } -/* { dg-final { scan-tree-dump "Attention! crc_xmodem_update function calculates CRC." "crc"} } */ +/* { dg-final { scan-tree-dump "crc_xmodem_update 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 "Executing \[a-zA-Z_\]\[a-zA-Z0-9_\]* = \[a-zA-Z_\]\[a-zA-Z0-9_\]* \\\^ \[a-zA-Z0-9_\]+\(\\\(\[a-zA-Z\]\\\)\)?;" "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 "crc_xmodem_update function calculates CRC!" "crc"} } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/crc-8.c b/gcc/testsuite/gcc.dg/crc-8.c index d04f42e541a2..ec990e1f78df 100644 --- a/gcc/testsuite/gcc.dg/crc-8.c +++ b/gcc/testsuite/gcc.dg/crc-8.c @@ -15,9 +15,10 @@ uint8_t _crc_ibutton_update(uint8_t crc, uint8_t data) { return crc; } -/* { dg-final { scan-tree-dump "Attention! _crc_ibutton_update function calculates CRC." "crc"} } */ +/* { dg-final { scan-tree-dump "_crc_ibutton_update 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 reversed" "crc"} } */ /* { dg-final { scan-tree-dump "Executing \[a-zA-Z_\]\[a-zA-Z0-9_\]* = \[a-zA-Z_\]\[a-zA-Z0-9_\]* \\\^ \[a-zA-Z0-9_\]+\(\\\(\[a-zA-Z\]\\\)\)?;" "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 "_crc_ibutton_update function calculates CRC!" "crc"} } */ diff --git a/gcc/testsuite/gcc.dg/crc-9.c b/gcc/testsuite/gcc.dg/crc-9.c index 6c644b4ed70e..d48e9ce532cf 100644 --- a/gcc/testsuite/gcc.dg/crc-9.c +++ b/gcc/testsuite/gcc.dg/crc-9.c @@ -20,7 +20,7 @@ uint8_t gencrc(uint8_t *data, size_t len) { return crc; } -/* { dg-final { scan-tree-dump "Attention! gencrc function calculates CRC." "crc"} } */ +/* { dg-final { scan-tree-dump "gencrc 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"} } */