This rewrites SSA operand checking to basically check that the operand status is the same as if you'd do an update_stmt on the stmt. The current checking code does not properly verify that all stmts are properly updated as it misses missing and swapped operands for example (bugs like that I've fixed in the past, always required some major debugging).
This means that the operand scanner implementation is the reference of what is supposed to be in the operand lists and what not. Thus, checking code and implementation will not go out of sync. Bootstrapped and tested on x86_64-unknown-linux-gnu. It exposes FAIL: gfortran.fortran-torture/compile/pr45738.f90, -O3 -g (internal compiler error) which is a bug introduced by 2011-12-01 Jakub Jelinek <ja...@redhat.com> PR debug/50317 * tree-ssa-live.c (remove_unused_locals): Clear TREE_ADDRESSABLE bit on local unreferenced variables. which produces invalid GIMPLE. Richard. 2011-12-02 Richard Guenther <rguent...@suse.de> * tree-ssa.c (verify_ssa): Verify SSA names in the loop over all SSA names. Remove SSA operand checking, call verify_ssa_operands. * tree-ssa-operands.h (verify_ssa_operands): Declare. * tree-ssa-operands.c (verify_ssa_operands): New function. Index: gcc/tree-ssa.c =================================================================== *** gcc/tree-ssa.c (revision 181902) --- gcc/tree-ssa.c (working copy) *************** verify_ssa (bool check_modified_stmt) *** 933,938 **** --- 933,940 ---- gimple stmt; TREE_VISITED (name) = 0; + verify_ssa_name (name, !is_gimple_reg (name)); + stmt = SSA_NAME_DEF_STMT (name); if (!gimple_nop_p (stmt)) { *************** verify_ssa (bool check_modified_stmt) *** 982,990 **** { gimple stmt = gsi_stmt (gsi); use_operand_p use_p; - bool has_err; - int count; - unsigned i; if (check_modified_stmt && gimple_modified_p (stmt)) { --- 984,989 ---- *************** verify_ssa (bool check_modified_stmt) *** 994,1082 **** goto err; } ! if (is_gimple_assign (stmt) ! && TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME) ! { ! tree lhs, base_address; ! ! lhs = gimple_assign_lhs (stmt); ! base_address = get_base_address (lhs); ! ! if (base_address ! && SSA_VAR_P (base_address) ! && !gimple_vdef (stmt) ! && optimize > 0) ! { ! error ("statement makes a memory store, but has no VDEFS"); ! print_gimple_stmt (stderr, stmt, 0, TDF_VOPS); ! goto err; ! } ! } ! else if (gimple_debug_bind_p (stmt) ! && !gimple_debug_bind_has_value_p (stmt)) ! continue; ! ! /* Verify the single virtual operand and its constraints. */ ! has_err = false; ! if (gimple_vdef (stmt)) ! { ! if (gimple_vdef_op (stmt) == NULL_DEF_OPERAND_P) ! { ! error ("statement has VDEF operand not in defs list"); ! has_err = true; ! } ! if (!gimple_vuse (stmt)) ! { ! error ("statement has VDEF but no VUSE operand"); ! has_err = true; ! } ! else if (SSA_NAME_VAR (gimple_vdef (stmt)) ! != SSA_NAME_VAR (gimple_vuse (stmt))) ! { ! error ("VDEF and VUSE do not use the same symbol"); ! has_err = true; ! } ! has_err |= verify_ssa_name (gimple_vdef (stmt), true); ! } ! if (gimple_vuse (stmt)) { ! if (gimple_vuse_op (stmt) == NULL_USE_OPERAND_P) ! { ! error ("statement has VUSE operand not in uses list"); ! has_err = true; ! } ! has_err |= verify_ssa_name (gimple_vuse (stmt), true); ! } ! if (has_err) ! { ! error ("in statement"); ! print_gimple_stmt (stderr, stmt, 0, TDF_VOPS|TDF_MEMSYMS); goto err; } ! count = 0; ! FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE|SSA_OP_DEF) ! { ! if (verify_ssa_name (op, false)) ! { ! error ("in statement"); ! print_gimple_stmt (stderr, stmt, 0, TDF_VOPS|TDF_MEMSYMS); ! goto err; ! } ! count++; ! } ! ! for (i = 0; i < gimple_num_ops (stmt); i++) ! { ! op = gimple_op (stmt, i); ! if (op && TREE_CODE (op) == SSA_NAME && --count < 0) ! { ! error ("number of operands and imm-links don%'t agree" ! " in statement"); ! print_gimple_stmt (stderr, stmt, 0, TDF_VOPS|TDF_MEMSYMS); ! goto err; ! } ! } FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE|SSA_OP_VUSE) { --- 993,1007 ---- goto err; } ! if (verify_ssa_operands (stmt)) { ! print_gimple_stmt (stderr, stmt, 0, TDF_VOPS); goto err; } ! if (gimple_debug_bind_p (stmt) ! && !gimple_debug_bind_has_value_p (stmt)) ! continue; FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE|SSA_OP_VUSE) { Index: gcc/tree-ssa-operands.h =================================================================== *** gcc/tree-ssa-operands.h (revision 181902) --- gcc/tree-ssa-operands.h (working copy) *************** extern void fini_ssa_operands (void); *** 105,110 **** --- 105,111 ---- extern void update_stmt_operands (gimple); extern void free_stmt_operands (gimple); extern bool verify_imm_links (FILE *f, tree var); + extern bool verify_ssa_operands (gimple stmt); extern void dump_immediate_uses (FILE *file); extern void dump_immediate_uses_for (FILE *file, tree var); Index: gcc/tree-ssa-operands.c =================================================================== *** gcc/tree-ssa-operands.c (revision 181902) --- gcc/tree-ssa-operands.c (working copy) *************** along with GCC; see the file COPYING3. *** 33,39 **** #include "ggc.h" #include "timevar.h" #include "langhooks.h" ! #include "ipa-reference.h" /* This file contains the code required to manage the operands cache of the SSA optimizer. For every stmt, we maintain an operand cache in the stmt --- 33,40 ---- #include "ggc.h" #include "timevar.h" #include "langhooks.h" ! #include "diagnostic-core.h" ! /* This file contains the code required to manage the operands cache of the SSA optimizer. For every stmt, we maintain an operand cache in the stmt *************** build_ssa_operands (gimple stmt) *** 1081,1086 **** --- 1082,1199 ---- finalize_ssa_stmt_operands (stmt); } + /* Verifies SSA statement operands. */ + + DEBUG_FUNCTION bool + verify_ssa_operands (gimple stmt) + { + use_operand_p use_p; + def_operand_p def_p; + ssa_op_iter iter; + unsigned i; + tree use, def; + bool volatile_p = gimple_has_volatile_ops (stmt); + + /* build_ssa_operands w/o finalizing them. */ + gimple_set_has_volatile_ops (stmt, false); + start_ssa_stmt_operands (); + parse_ssa_operands (stmt); + + /* Now verify the built operands are the same as present in STMT. */ + def = gimple_vdef (stmt); + if (def + && TREE_CODE (def) == SSA_NAME) + def = SSA_NAME_VAR (def); + if (build_vdef != def) + { + error ("virtual definition of statement not up-to-date"); + return true; + } + if (gimple_vdef (stmt) + && ((def_p = gimple_vdef_op (stmt)) == NULL_DEF_OPERAND_P + || DEF_FROM_PTR (def_p) != gimple_vdef (stmt))) + { + error ("virtual def operand missing for stmt"); + return true; + } + + use = gimple_vuse (stmt); + if (use + && TREE_CODE (use) == SSA_NAME) + use = SSA_NAME_VAR (use); + if (build_vuse != use) + { + error ("virtual use of statement not up-to-date"); + return true; + } + if (gimple_vuse (stmt) + && ((use_p = gimple_vuse_op (stmt)) == NULL_USE_OPERAND_P + || USE_FROM_PTR (use_p) != gimple_vuse (stmt))) + { + error ("virtual use operand missing for stmt"); + return true; + } + + FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE) + { + FOR_EACH_VEC_ELT (tree, build_uses, i, use) + { + if (use_p->use == (tree *)use) + { + VEC_replace (tree, build_uses, i, NULL_TREE); + break; + } + } + if (i == VEC_length (tree, build_uses)) + { + error ("excess use operand for stmt"); + debug_generic_expr (USE_FROM_PTR (use_p)); + return true; + } + } + FOR_EACH_VEC_ELT (tree, build_uses, i, use) + if (use != NULL_TREE) + { + error ("use operand missing for stmt"); + debug_generic_expr (*(tree *)use); + return true; + } + + FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, iter, SSA_OP_DEF) + { + FOR_EACH_VEC_ELT (tree, build_defs, i, def) + { + if (def_p == (tree *)def) + { + VEC_replace (tree, build_defs, i, NULL_TREE); + break; + } + } + if (i == VEC_length (tree, build_defs)) + { + error ("excess def operand for stmt"); + debug_generic_expr (DEF_FROM_PTR (def_p)); + return true; + } + } + FOR_EACH_VEC_ELT (tree, build_defs, i, def) + if (def != NULL_TREE) + { + error ("def operand missing for stmt"); + debug_generic_expr (*(tree *)def); + return true; + } + + if (gimple_has_volatile_ops (stmt) != volatile_p) + { + error ("stmt volatile flag not up-to-date"); + return true; + } + + cleanup_build_arrays (); + return false; + } + /* Releases the operands of STMT back to their freelists, and clears the stmt operand lists. */