Commit 1d523ad2 authored by Matthias Braun's avatar Matthias Braun
Browse files

trverify: cleanup, check irg.entity == entity.irg

parent 6c4a3cb5
......@@ -227,11 +227,9 @@ FIRM_API ir_entity *new_d_parameter_entity(ir_type *owner, size_t pos,
* Check an entity. Currently, we check only if initialized constants
* are build on the const irg graph.
*
* @return
* 0 if no error encountered
* != 0 a trverify_error_codes code
* @return non-zero if no errors were found
*/
FIRM_API int check_entity(ir_entity *ent);
FIRM_API int check_entity(const ir_entity *ent);
/**
* Copies the entity if the new_owner is different from the
......@@ -482,7 +480,7 @@ FIRM_API int is_irn_const_expression(ir_node *n);
FIRM_API ir_node *copy_const_value(dbg_info *dbg, ir_node *n, ir_node *to_block);
/** Returns initial value of entity with atomic type @p ent. */
FIRM_API ir_node *get_atomic_ent_value(ir_entity *ent);
FIRM_API ir_node *get_atomic_ent_value(const ir_entity *ent);
/** Sets initial value of entity with atomic type @p ent to node @p val.
* @note @p val must be a node in the const_code graph */
FIRM_API void set_atomic_ent_value(ir_entity *ent, ir_node *val);
......@@ -1032,29 +1030,12 @@ FIRM_API void set_irp_class_cast_state(ir_class_cast_state state);
/** Returns class cast state for the whole program. */
FIRM_API ir_class_cast_state get_irp_class_cast_state(void);
/**
* possible trverify() error codes
*/
enum trverify_error_codes {
no_error = 0, /**< no error */
error_ent_not_cont, /**< overwritten entity not in superclass */
error_null_mem, /**< compound contains NULL member */
error_const_on_wrong_irg, /**< constant placed on wrong IRG */
error_existent_entity_without_irg, /**< Method entities with pecularity_exist must have an irg */
error_wrong_ent_overwrites, /**< number of entity overwrites exceeds number of class overwrites */
error_inherited_ent_without_const, /**< inherited method entity not pointing to existent entity */
error_glob_ent_allocation, /**< wrong allocation of a global entity */
error_ent_const_mode, /**< Mode of constant in entity did not match entities type. */
error_ent_wrong_owner /**< Mode of constant in entity did not match entities type. */
};
/**
* Checks a type.
*
* @return
* 0 if no error encountered
* @return non-zero if no errors were found
*/
FIRM_API int check_type(ir_type *tp);
FIRM_API int check_type(const ir_type *tp);
/**
* Walks the type information and performs a set of sanity checks.
......@@ -1064,9 +1045,7 @@ FIRM_API int check_type(ir_type *tp);
* - class types: doesn't have NULL members
* - class types: all overwrites are existent in the super type
*
* @return
* 0 if graph is correct
* else error code.
* @return 0 if no error encountered
*/
FIRM_API int tr_verify(void);
......
......@@ -492,7 +492,7 @@ void (set_entity_usage)(ir_entity *ent, ir_entity_usage flags)
_set_entity_usage(ent, flags);
}
ir_node *get_atomic_ent_value(ir_entity *entity)
ir_node *get_atomic_ent_value(const ir_entity *entity)
{
ir_initializer_t *initializer = get_entity_initializer(entity);
......
......@@ -33,279 +33,146 @@
#include "tv.h"
#include "ircons.h"
#ifdef NDEBUG
/*
* in RELEASE mode, returns ret if the expression expr evaluates to zero
* in ASSERT mode, asserts the expression expr (and the string string).
*/
#define ASSERT_AND_RET(expr, string, ret) if (!(expr)) return (ret)
static void report_error(const char *fmt, ...)
{
va_list ap;
/*
* in RELEASE mode, returns ret if the expression expr evaluates to zero
* in ASSERT mode, executes blk if the expression expr evaluates to zero and asserts expr
*/
#define ASSERT_AND_RET_DBG(expr, string, ret, blk) if (!(expr)) return (ret)
#else
#define ASSERT_AND_RET(expr, string, ret) \
do { \
if (opt_do_node_verification == FIRM_VERIFICATION_ON) {\
assert((expr) && string); } \
if (!(expr)) { \
if (opt_do_node_verification == FIRM_VERIFICATION_REPORT) \
fprintf(stderr, #expr " : " string "\n"); \
firm_verify_failure_msg = #expr " && " string; \
return (ret); \
} \
} while (0)
#define ASSERT_AND_RET_DBG(expr, string, ret, blk) \
do { \
if (!(expr)) { \
firm_verify_failure_msg = #expr " && " string; \
if (opt_do_node_verification != FIRM_VERIFICATION_ERROR_ONLY) { blk; } \
if (opt_do_node_verification == FIRM_VERIFICATION_REPORT) \
fprintf(stderr, #expr " : " string "\n"); \
else if (opt_do_node_verification == FIRM_VERIFICATION_ON) { \
assert((expr) && string); \
} \
return (ret); \
} \
} while (0)
#endif /* NDEBUG */
#ifndef NDEBUG
static const char *firm_verify_failure_msg;
#if 0
/**
* Show diagnostic if an entity overwrites another one not
* in direct superclasses.
*/
static void show_ent_not_supertp(ir_entity *ent, ir_entity *ovw)
fprintf(stderr, "Verify warning: ");
va_start(ap, fmt);
ir_vfprintf(stderr, fmt, ap);
va_end(ap);
fputc('\n', stderr);
}
static bool check_class_member(const ir_type *tp, const ir_entity *entity)
{
ir_type *owner = get_entity_owner(ent);
ir_type *ov_own = get_entity_owner(ovw);
size_t i;
fprintf(stderr, "Type verification error:\n");
ir_fprintf(stderr, "Entity %+F::%+e owerwrites ", owner, ent);
ir_fprintf(stderr, "Entity %+F::%+e\n", ov_own, ovw);
ir_fprintf(stderr, "Supertypes of %+F:\n", owner);
for (i = 0; i < get_class_n_supertypes(owner); ++i) {
ir_type *super = get_class_supertype(owner, i);
ir_fprintf(stderr, " %+F:\n", super);
bool fine = true;
if (get_entity_n_overwrites(entity) > get_class_n_supertypes(tp)) {
report_error("member %+F of %+F has too many overwrites", entity, tp);
fine = false;
}
return fine;
}
#endif
/**
* Show diagnostic if an entity overwrites a wrong number of things.
*/
static void show_ent_overwrite_cnt(ir_entity *ent)
static bool check_compound_type(const ir_type *tp)
{
ir_type *owner = get_entity_owner(ent);
bool fine = true;
bool is_class = is_Class_type(tp);
size_t n = get_compound_n_members(tp);
size_t i;
size_t j;
size_t k;
bool found;
bool show_stp = false;
fprintf(stderr, "Type verification error:\n");
ir_fprintf(stderr, "Entity %t::%e owerwrites\n", owner, ent);
for (i = 0; i < get_entity_n_overwrites(ent); ++i) {
ir_entity *ovw = get_entity_overwrites(ent, i);
ir_type *ov_own = get_entity_owner(ovw);
size_t n_supertypes = get_class_n_supertypes(owner);
ir_fprintf(stderr, " %t::%e\n", ov_own, ovw);
for (k = 0; k < i; ++k) {
if (ovw == get_entity_overwrites(ent, k)) {
ir_fprintf(stderr, " ->%t::%e entered more than once\n", ov_own, ovw);
break;
}
}
found = false;
for (j = 0; j < n_supertypes; ++j) {
if (ov_own == get_class_supertype(owner, j)) {
show_stp = found = true;
break;
}
}
if (! found)
ir_fprintf(stderr, " ->%t not in super types of %t\n", ov_own, owner);
}
for (i = 0; i < n; ++i) {
ir_entity *member = get_compound_member(tp, i);
ir_type *owner;
if (show_stp) {
ir_fprintf(stderr, "Supertypes of %t:\n", owner);
for (i = 0; i < get_class_n_supertypes(owner); ++i) {
ir_type *super = get_class_supertype(owner, i);
ir_fprintf(stderr, " %t:\n", super);
if (member == NULL) {
report_error("%+F has a NULL member\n", tp);
fine = false;
continue;
}
owner = get_entity_owner(member);
if (owner != tp) {
report_error("member %+F of %+F has owner %+F\n", member, tp, owner);
fine = false;
}
if (is_class) {
fine &= check_class_member(tp, member);
}
}
return fine;
}
#endif /* #ifndef NDEBUG */
/**
* Check a class
*/
static int check_class(ir_type *tp)
static bool check_array_type(const ir_type *tp)
{
size_t i, n;
for (i = 0, n = get_class_n_members(tp); i < n; ++i) {
ir_entity *mem = get_class_member(tp, i);
ASSERT_AND_RET_DBG(
tp == get_entity_owner(mem),
"class member with wrong owner",
error_ent_wrong_owner,
ir_fprintf(stderr, "Type verification error:\n%+F %+e(owner %+F)\n",tp, mem, get_entity_owner(mem))
);
ASSERT_AND_RET_DBG(
mem,
"NULL members not allowed",
error_null_mem,
ir_fprintf(stderr, "Type verification error:\n%+F member %zu is NULL\n", tp, i)
);
ASSERT_AND_RET_DBG(
get_entity_n_overwrites(mem) <= get_class_n_supertypes(tp),
"wrong number of entity overwrites",
error_wrong_ent_overwrites,
show_ent_overwrite_cnt(mem)
);
#if 0
{
size_t j, m;
/* check if the overwrite relation is flat, i.e. every overwrite
* is visible in every direct superclass. */
for (j = 0, m = get_entity_n_overwrites(mem); j < m; ++j) {
ir_entity *ovw = get_entity_overwrites(mem, j);
size_t k, n_super;
/* Check whether ovw is member of one of tp's supertypes. If so,
the representation is correct. */
for (k = 0, n_super = get_class_n_supertypes(tp); k < n_super; ++k) {
if (get_class_member_index(get_class_supertype(tp, k), ovw) != INVALID_MEMBER_INDEX) {
ASSERT_AND_RET_DBG(
0,
"overwrites an entity not contained in direct supertype",
error_ent_not_cont,
show_ent_not_supertp(mem, ovw)
);
break;
}
}
}
bool fine = true;
size_t n_dim = get_array_n_dimensions(tp);
size_t i;
for (i = 0; i < n_dim; ++i) {
if (!has_array_lower_bound(tp, i) && !has_array_upper_bound(tp, i)) {
report_error("missing array bound in %+F in dimension %zu", tp, i);
fine = false;
}
#endif
}
return 0;
return fine;
}
/**
* Check an array.
*/
static int check_array(const ir_type *tp)
static bool check_type_mode(const ir_type *tp)
{
size_t i, n_dim = get_array_n_dimensions(tp);
for (i = 0; i < n_dim; ++i) {
ASSERT_AND_RET_DBG(
has_array_lower_bound(tp, i) || has_array_upper_bound(tp, i),
"array bound missing",
1,
ir_fprintf(stderr, "%+F in dimension %zu\n", tp, i)
);
bool fine = true;
if (get_type_mode(tp) == NULL) {
report_error("type %+F has no mode", tp);
fine = false;
}
return 0;
return fine;
}
static bool check_primitive_type(const ir_type *tp)
{
return check_type_mode(tp);
}
/**
* Check a primitive.
*/
static int check_primitive(ir_type *tp)
static bool check_pointer_type(const ir_type *tp)
{
ASSERT_AND_RET_DBG(
is_mode(get_type_mode(tp)),
"Primitive type without mode",
1,
ir_fprintf(stderr, "%+F\n", tp)
);
return 0;
return check_type_mode(tp);
}
int check_type(ir_type *tp)
int check_type(const ir_type *tp)
{
switch (get_type_tpop_code(tp)) {
case tpo_class:
return check_class(tp);
case tpo_array:
return check_array(tp);
case tpo_primitive:
return check_primitive(tp);
default: break;
case tpo_union:
case tpo_struct:
case tpo_class: return check_compound_type(tp);
case tpo_array: return check_array_type(tp);
case tpo_primitive: return check_primitive_type(tp);
case tpo_pointer: return check_pointer_type(tp);
case tpo_enumeration:
case tpo_method:
case tpo_uninitialized:
case tpo_unknown:
case tpo_none:
case tpo_code:
break;
}
return 0;
return true;
}
/**
* checks the visited flag
*/
static int check_visited_flag(ir_graph *irg, ir_node *n)
static bool check_visited_flag(ir_graph *irg, ir_node *n)
{
ASSERT_AND_RET_DBG(
get_irn_visited(n) <= get_irg_visited(irg),
"Visited flag of node is larger than that of corresponding irg.",
0,
ir_fprintf(stderr, "%+F in %+F\n", n, irg)
);
return 1;
bool fine = true;
if (get_irn_visited(n) > get_irg_visited(irg)) {
report_error("visited flag of %+F is larger than that of corresponding irg %+F", n, irg);
fine = false;
}
return fine;
}
/**
* helper environment struct for constant_on_wrong_obstack()
*/
typedef struct myenv {
int res;
ir_graph *irg;
bool fine;
} myenv;
/**
* called by the walker
*/
static void on_irg_storage(ir_node *n, void *data)
{
myenv *env = (myenv*)data;
/* We also test whether the setting of the visited flag is legal. */
env->res = node_is_in_irgs_storage(env->irg, n) &&
check_visited_flag(env->irg, n);
env->fine &= node_is_in_irgs_storage(env->irg, n);
env->fine &= check_visited_flag(env->irg, n);
}
/**
* checks whether a given constant IR node is NOT on the
* constant IR graph.
*/
static int constant_on_wrong_irg(ir_node *n)
static bool constant_on_wrong_irg(ir_node *n)
{
myenv env;
env.res = 1; /* on right obstack */
env.irg = get_const_code_irg();
env.fine = true;
env.irg = get_const_code_irg();
irg_walk(n, on_irg_storage, NULL, (void *)&env);
return ! env.res;
return env.fine;
}
static int initializer_constant_on_wrong_irg(ir_initializer_t *initializer)
static bool initializer_constant_on_wrong_irg(const ir_initializer_t *initializer)
{
switch (get_initializer_kind(initializer)) {
case IR_INITIALIZER_NULL:
......@@ -315,64 +182,60 @@ static int initializer_constant_on_wrong_irg(ir_initializer_t *initializer)
case IR_INITIALIZER_CONST:
return constant_on_wrong_irg(get_initializer_const_value(initializer));
case IR_INITIALIZER_COMPOUND: {
size_t i, n = get_initializer_compound_n_entries(initializer);
bool fine = true;
size_t n = get_initializer_compound_n_entries(initializer);
size_t i;
for (i = 0; i < n; ++i) {
ir_initializer_t *sub
const ir_initializer_t *sub
= get_initializer_compound_value(initializer, i);
if (initializer_constant_on_wrong_irg(sub))
return 1;
fine &= initializer_constant_on_wrong_irg(sub);
}
return 0;
return fine;
}
}
panic("invalid initializer in initializer_on_wrong_irg");
}
/**
* Check if constants node are NOT on the constant IR graph.
*
* @return NON-zero if an entity initializer constant is NOT on
* the current_ir_graph's obstack.
*/
static int constants_on_wrong_irg(ir_entity *ent)
static bool constants_on_wrong_irg(const ir_entity *ent)
{
if (ent->initializer != NULL) {
return initializer_constant_on_wrong_irg(ent->initializer);
} else if (entity_has_compound_ent_values(ent)) {
size_t i, n;
for (i = 0, n = get_compound_ent_n_values(ent); i < n; ++i) {
if (constant_on_wrong_irg(get_compound_ent_value(ent, i)))
return 1;
bool fine = true;
size_t n = get_compound_ent_n_values(ent);
size_t i;
for (i = 0; i < n; ++i) {
fine &= constant_on_wrong_irg(get_compound_ent_value(ent, i));
}
return fine;
}
return 0;
return true;
}
int check_entity(ir_entity *ent)
int check_entity(const ir_entity *ent)
{
ir_type *tp = get_entity_type(ent);
current_ir_graph = get_const_code_irg();
ASSERT_AND_RET_DBG(
constants_on_wrong_irg(ent) == 0,
"Contants placed on wrong IRG",
error_const_on_wrong_irg,
ir_fprintf(stderr, "%+e not on %+F\n", ent, current_ir_graph)
);
/* Originally, this test assumed, that only method entities have
pecularity_inherited. As I changed this, I have to test for method type
before doing the test. */
if (get_entity_peculiarity(ent) == peculiarity_existent
&& is_method_entity(ent)) {
ir_entity *impl = get_SymConst_entity(get_atomic_ent_value(ent));
ASSERT_AND_RET_DBG(
impl != NULL,
"inherited method entities must have constant pointing to existent entity.",
error_inherited_ent_without_const,
ir_fprintf(stderr, "%+e points to %+e\n", ent, impl)
);
bool fine = true;
ir_type *tp = get_entity_type(ent);
fine &= constants_on_wrong_irg(ent);
if (is_method_entity(ent)) {
ir_graph *irg = get_entity_irg(ent);
if (irg != NULL) {
ir_entity *irg_entity = get_irg_entity(irg);
if (irg_entity != ent) {
report_error("entity(%+F)->irg->entity(%+F) relation invalid",
ent, irg_entity);
fine = false;
}
}
if (get_entity_peculiarity(ent) == peculiarity_existent) {
ir_entity *impl = get_SymConst_entity(get_atomic_ent_value(ent));
if (impl == NULL) {
report_error("inherited method entity %+F must have constant pointing to existent entity.", ent);
fine = false;
}
}
}
if (is_atomic_entity(ent) && ent->initializer != NULL) {
......@@ -389,88 +252,94 @@ int check_entity(ir_entity *ent)
case IR_INITIALIZER_COMPOUND:
break;
}
ASSERT_AND_RET_DBG(
mode == NULL || mode == get_type_mode(tp),
"Mode of constant in entity must match type.",
error_ent_const_mode,
ir_fprintf(stderr, "%+e, type %+F(%+F)\n",
ent, tp, get_type_mode(tp))
);
if (mode != NULL && mode != get_type_mode(tp)) {
report_error("initializer of entity %+F has wrong mode.", ent);
fine = false;
}
}
return no_error;
return fine;
}
/*
* check types and entities
*/
static void check_tore(type_or_ent tore, void *env)
{
int *res = (int*)env;
assert(tore.ent);
bool *fine = (bool*)env;
if (is_type(tore.typ)) {
*res = check_type(tore.typ);
*fine &= check_type(tore.typ);
} else {
assert(is_entity(tore.ent));
*res = check_entity(tore.ent);
*fine &= check_entity(tore.ent);
}
}
int tr_verify(void)
{
static ident *empty = NULL;
int res = no_error;
bool fine = true;
ir_type *constructors;
ir_type *destructors;
ir_type *thread_locals;
size_t i, n;
ir_segment_t s;
if (empty == NULL)
empty = new_id_from_chars("", 0);
type_walk(check_tore, NULL, &res);
type_walk(check_tore, NULL, &fine);
for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
const ir_type *type = get_segment_type(s);
size_t e;
for (e = 0; e < get_compound_n_members(type); ++e) {
ir_entity *entity = get_compound_member(type, e);
ASSERT_AND_RET(get_entity_ld_ident(entity) != NULL ||
get_entity_visibility(entity) == ir_visibility_private,
"segment members must have a name or visibility_private",
1);
if (get_entity_ld_ident(entity) == NULL &&
get_entity_visibility(entity) != ir_visibility_private) {
report_error("public segment member %+F has no name",
entity);
fine = false;
}
}
}
constructors = get_segment_type(IR_SEGMENT_CONSTRUCTORS);
for (i = 0, n = get_compound_n_members(constructors); i < n; ++i) {
const ir_entity *entity = get_compound_member(constructors, i);
ASSERT_AND_RET(get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER,
"entity without LINKAGE_HIDDEN_USER in constructors is pointless",
1);
if ((get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER) == 0) {
report_error("entity %+F in constructors without LINKAGE_HIDDEN_USER",
entity);