X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Ftr%2Ftrverify.c;h=470dbbfe37b207655c87417b4d6fdc8ac3ea0990;hb=2b84102b8f003a13d083330fbc6aaff92b6563e9;hp=d3ac10e11cf4fedc720c73224056b50180b30c71;hpb=fb2a783c4d6e8a2c203c6ce9833ac50d381fa2e1;p=libfirm diff --git a/ir/tr/trverify.c b/ir/tr/trverify.c index d3ac10e11..470dbbfe3 100644 --- a/ir/tr/trverify.c +++ b/ir/tr/trverify.c @@ -22,7 +22,6 @@ * @brief Check types and entities for correctness. * @date 29.1.2003 * @author Michael Beck, Goetz Lindenmaier - * @version $Id$ */ #include "config.h" @@ -32,278 +31,148 @@ #include "irgwalk.h" #include "error.h" #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; + fprintf(stderr, "Verify warning: "); + va_start(ap, fmt); + ir_vfprintf(stderr, fmt, ap); + va_end(ap); + fputc('\n', stderr); +} -/** - * Show diagnostic if an entity overwrites another one not - * in direct superclasses. - */ -static void show_ent_not_supertp(ir_entity *ent, ir_entity *ovw) +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; } -/** - * 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, j, m; - - 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) - ); - - 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; } } - 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; } - -/** - * Check a primitive. - */ -static int check_primitive(ir_type *tp) +static bool check_primitive_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); } +static bool check_pointer_type(const ir_type *tp) +{ + return check_type_mode(tp); +} -/* - * Checks a type. - * - * return - * 0 if no error encountered - */ -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: @@ -313,78 +182,93 @@ 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: { - int n = get_initializer_compound_n_entries(initializer); - int i; + 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"); + panic("invalid initializer"); } -/** - * 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; - } } - return 0; + return true; } -/* - * 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 - */ -int check_entity(ir_entity *ent) +static bool check_external_linkage(const ir_entity *entity, ir_linkage linkage, + const char *linkage_name) +{ + bool fine = true; + if ((get_entity_linkage(entity) & linkage) == 0) + return true; + if (get_entity_visibility(entity) != ir_visibility_external) { + report_error("entity %+F has IR_LINKAGE_%s but is not externally visible", entity, linkage_name); + fine = false; + } + if (!entity_has_definition(entity)) { + report_error("entity %+F has IR_LINKAGE_%s but is just a declaration", entity, linkage_name); + fine = false; + } + return fine; +} + +int check_entity(const ir_entity *entity) { - 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(entity); + ir_linkage linkage = get_entity_linkage(entity); + + fine &= constants_on_wrong_irg(entity); + + if (is_method_entity(entity)) { + ir_graph *irg = get_entity_irg(entity); + if (irg != NULL) { + ir_entity *irg_entity = get_irg_entity(irg); + if (irg_entity != entity) { + report_error("entity(%+F)->irg->entity(%+F) relation invalid", + entity, irg_entity); + fine = false; + } + } + if (get_entity_peculiarity(entity) == peculiarity_existent) { + ir_entity *impl = get_SymConst_entity(get_atomic_ent_value(entity)); + if (impl == NULL) { + report_error("inherited method entity %+F must have constant pointing to existent entity.", entity); + fine = false; + } + } + } + + if (linkage & IR_LINKAGE_NO_CODEGEN) { + if (!is_method_entity(entity)) { + report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but is not a function", entity); + fine = false; + } else if (get_entity_irg(entity) == NULL) { + report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but has no ir-graph anyway", entity); + fine = false; + } + if (get_entity_visibility(entity) != ir_visibility_external) { + report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but is not externally visible", entity); + fine = false; + } } + check_external_linkage(entity, IR_LINKAGE_WEAK, "WEAK"); + check_external_linkage(entity, IR_LINKAGE_GARBAGE_COLLECT, + "GARBAGE_COLLECT"); + check_external_linkage(entity, IR_LINKAGE_MERGE, "MERGE"); - if (is_atomic_entity(ent) && ent->initializer != NULL) { + if (is_atomic_entity(entity) && entity->initializer != NULL) { ir_mode *mode = NULL; - ir_initializer_t *initializer = ent->initializer; + ir_initializer_t *initializer = entity->initializer; switch (initializer->kind) { case IR_INITIALIZER_CONST: mode = get_irn_mode(get_initializer_const_value(initializer)); @@ -396,91 +280,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.", entity); + 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); } } -/* - * Verify types and entities. - */ 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); + fine = false; + } /* Mach-O doesn't like labels in this section */ - ASSERT_AND_RET(get_entity_ld_ident(entity), - "entity in constructors should have ld_ident=''", 1); + if (get_entity_ld_name(entity)[0] != '\0') { + report_error("entity %+F in constructors must not have an ld_name", + entity); + fine = false; + } } destructors = get_segment_type(IR_SEGMENT_DESTRUCTORS); for (i = 0, n = get_compound_n_members(destructors); i < n; ++i) { const ir_entity *entity = get_compound_member(destructors, i); - ASSERT_AND_RET(get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER, - "entity without LINKAGE_HIDDEN_USER in destructors is pointless", - 1); + if ((get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER) == 0) { + report_error("entity %+F in destructors without LINKAGE_HIDDEN_USER", + entity); + fine = false; + } /* Mach-O doesn't like labels in this section */ - ASSERT_AND_RET(get_entity_ld_ident(entity), - "entity in destructors should have ld_ident=''", 1); + if (get_entity_ld_name(entity)[0] != '\0') { + report_error("entity %+F in destructors must not have an ld_name", + entity); + fine = false; + } } thread_locals = get_segment_type(IR_SEGMENT_THREAD_LOCAL); for (i = 0, n = get_compound_n_members(thread_locals); i < n; ++i) { const ir_entity *entity = get_compound_member(thread_locals, i); /* this is odd and should not be allowed I think */ - ASSERT_AND_RET(!is_method_entity(entity), - "method in THREAD_LOCAL segment", 1); - ASSERT_AND_RET(! (get_entity_linkage(entity) & IR_LINKAGE_CONSTANT), - "thread locals must not be constant", 1); + if (is_method_entity(entity)) { + report_error("method %+F in thread local segment"); + fine = false; + } + if (get_entity_linkage(entity) & IR_LINKAGE_CONSTANT) { + report_error("entity %+F in thread local segment is constant"); + fine = false; + } } - return res; + return fine; }