X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Ftr%2Ftypewalk.c;h=c510a4e0fbb5d6d23c3b01144de3686169d8155c;hb=226c238839ce84c2c310c8e7522838160c6f71af;hp=36bfb5fa41beb56648384227ed2ec97461cf8e94;hpb=c201fe69b5fcb5a8430afafe2e15946cab4e45c4;p=libfirm diff --git a/ir/tr/typewalk.c b/ir/tr/typewalk.c index 36bfb5fa4..c510a4e0f 100644 --- a/ir/tr/typewalk.c +++ b/ir/tr/typewalk.c @@ -1,175 +1,560 @@ -/* Copyright (C) 1998 - 2000 by Universitaet Karlsruhe -** All rights reserved. -** -** Author: Goetz Lindenmaier -** -** traverse the type information. The walker walks the whole ir graph -** to find the distinct type trees in the type graph forest. -** - execute the pre function before recursion -** - execute the post function after recursion -*/ - -#include "stdio.h" -#include "irgwalk.h" -#include "irgraph.h" -#include "irnode.h" -#include "type_or_entity.h" +/* + * This file is part of libFirm. + * Copyright (C) 2012 University of Karlsruhe. + */ + +/** + * @file + * @brief Functionality to modify the type graph. + * @author Goetz Lindenmaier + * @brief + * + * Traverse the type information. The walker walks the whole ir graph + * to find the distinct type trees in the type graph forest. + * - execute the pre function before recursion + * - execute the post function after recursion + */ +#include "config.h" + +#include +#include -/* Make types visible to allow most efficient access */ -# include "entity_t.h" +#include "entity_t.h" +#include "type_t.h" +#include "irprog_t.h" +#include "irgraph_t.h" +#include "irnode_t.h" +#include "irgwalk.h" +#include "error.h" +#include "ircons.h" + +/** + * The walker environment + */ typedef struct type_walk_env { - void *pre; - void *post; - void *env; + type_walk_func *pre; /**< Pre-walker function */ + type_walk_func *post; /**< Post-walker function */ + void *env; /**< environment for walker functions */ } type_walk_env; +/* a walker for irn's */ +static void irn_type_walker( + ir_node *node, type_walk_func *pre, type_walk_func *post, void *env); -void type_walk_2(type_or_ent *tore, - void (pre)(type_or_ent*, void*), void (post)(type_or_ent*, void*), - void *env) +static void walk_initializer(ir_initializer_t *initializer, + type_walk_func *pre, type_walk_func *post, + void *env) { - int i, visited = 0; - - /* marked? */ - switch (get_kind(tore)) { - case k_entity: - if (((entity *)tore)->visit >= type_visited) visited = 1; break; - case k_type_class: - if (((type_class *)tore)->visit >= type_visited) visited = 1; break; - case k_type_strct: - if (((type_strct *)tore)->visit >= type_visited) visited = 1; break; - case k_type_method: - if (((type_method *)tore)->visit >= type_visited) visited = 1; break; - case k_type_union: - if (((type_union *)tore)->visit >= type_visited) visited = 1; break; - case k_type_array: - if (((type_array *)tore)->visit >= type_visited) visited = 1; break; - case k_type_enumeration: - if (((type_enumeration *)tore)->visit >= type_visited) visited = 1; break; - case k_type_pointer: - if (((type_pointer *)tore)->visit >= type_visited) visited = 1; break; - case k_type_primitive: - if (((type_primitive *)tore)->visit >= type_visited) visited = 1; break; - default: - break; - } - - if (!visited) { /* not marked. */ - - /* execute pre method */ - if(pre) - pre(tore, env); - - /* iterate */ - switch (get_kind(tore)) { - case k_entity: - { - entity *ent = (entity *)tore; - ent->visit = type_visited; - type_walk_2((type_or_ent *)get_entity_owner(ent), pre, post, env); - type_walk_2((type_or_ent *)get_entity_type(ent), pre, post, env); - } - break; - case k_type_class: - ((type_class *)tore)->visit = type_visited; - /* !!!!! */ - break; - case k_type_strct: - ((type_strct *)tore)->visit = type_visited; - /* !!!!! */ - break; - case k_type_method: - { - type_method *meth = (type_method *)tore; - meth->visit = type_visited; - for (i = 0; i < get_method_arity(meth); i++) - type_walk_2((type_or_ent *)get_method_param_type(meth, i), pre, post, env); - for (i = 0; i < get_method_n_res(meth); i++) - type_walk_2((type_or_ent *)get_method_res_type(meth, i), pre, post, env); - } - break; - case k_type_union: - ((type_union *)tore)->visit = type_visited; - break; - case k_type_array: - ((type_array *)tore)->visit = type_visited; - type_walk_2((type_or_ent *)get_array_element_type((type_array *)tore), - pre, post, env); - break; - case k_type_enumeration: - ((type_enumeration *)tore)->visit = type_visited; - /* a leave */ - break; - case k_type_pointer: - ((type_pointer *)tore)->visit = type_visited; - type_walk_2((type_or_ent *)get_pointer_points_to_type((type_pointer *)tore), - pre, post, env); - break; - case k_type_primitive: - ((type_primitive *)tore)->visit = type_visited; - /* a leave. */ - break; - default: - break; - } - - /* execute post method */ - if(post) - post(tore, env); - } - - return; + switch (initializer->kind) { + case IR_INITIALIZER_CONST: + irn_type_walker(initializer->consti.value, pre, post, env); + return; + case IR_INITIALIZER_TARVAL: + case IR_INITIALIZER_NULL: + return; + + case IR_INITIALIZER_COMPOUND: { + size_t i; + for (i = 0; i < initializer->compound.n_initializers; ++i) { + ir_initializer_t *subinitializer + = initializer->compound.initializers[i]; + walk_initializer(subinitializer, pre, post, env); + } + return; + } + } + panic("invalid initializer found"); } -void start_type_walk(ir_node *node, void *env) { - void *pre = ((type_walk_env *)env)->pre; - void *post = ((type_walk_env *)env)->post; - void *envi = ((type_walk_env *)env)->env; - - assert(node); - - switch (get_irn_opcode(node)) { /* node label */ - case iro_SymConst: - if ( (get_SymConst_kind(node) == type_tag) - || (get_SymConst_kind(node) == size)) - type_walk_2((type_or_ent *)get_SymConst_type(node), pre, post, envi); - break; - case iro_Sel: - type_walk_2((type_or_ent *)get_Sel_entity(node), pre, post, envi); - break; - case iro_Call: - type_walk_2((type_or_ent *)get_Call_type(node), pre, post, envi); - break; - case iro_Alloc: - type_walk_2((type_or_ent *)get_Alloc_type(node), pre, post, envi); - break; - case iro_Free: - printf("here in typewalk\n"); - type_walk_2((type_or_ent *)get_Free_type(node), pre, post, envi); - break; - assert(node); - default: - break; - } +/** + * Main walker: walks over all used types/entities of a + * type entity. + */ +static void do_type_walk(type_or_ent tore, + type_walk_func *pre, + type_walk_func *post, + void *env) +{ + size_t i, n_types, n_mem; + ir_entity *ent = NULL; + ir_type *tp = NULL; + type_or_ent cont; + + /* marked? */ + switch (get_kind(tore.ent)) { + case k_entity: + ent = tore.ent; + if (entity_visited(ent)) + return; + mark_entity_visited(ent); + break; + case k_type: + tp = tore.typ; + if (type_visited(tp)) + return; + mark_type_visited(tp); + break; + default: + break; + } + + /* execute pre method */ + if (pre) + pre(tore, env); + + /* iterate */ + switch (get_kind(tore.ent)) { + case k_entity: + cont.typ = get_entity_owner(ent); + do_type_walk(cont, pre, post, env); + cont.typ = get_entity_type(ent); + do_type_walk(cont, pre, post, env); + + /* walk over the value types */ + if (ent->initializer != NULL) { + walk_initializer(ent->initializer, pre, post, env); + } + break; + case k_type: + switch (get_type_tpop_code(tp)) { + case tpo_class: + n_types = get_class_n_supertypes(tp); + for (i = 0; i < n_types; ++i) { + cont.typ = get_class_supertype(tp, i); + do_type_walk(cont, pre, post, env); + } + n_mem = get_class_n_members(tp); + for (i = 0; i < n_mem; ++i) { + cont.ent = get_class_member(tp, i); + do_type_walk(cont, pre, post, env); + } + n_types = get_class_n_subtypes(tp); + for (i = 0; i < n_types; ++i) { + cont.typ = get_class_subtype(tp, i); + do_type_walk(cont, pre, post, env); + } + break; + + case tpo_struct: + n_mem = get_struct_n_members(tp); + for (i = 0; i < n_mem; ++i) { + cont.ent = get_struct_member(tp, i); + do_type_walk(cont, pre, post, env); + } + break; + + case tpo_method: + n_mem = get_method_n_params(tp); + for (i = 0; i < n_mem; ++i) { + cont.typ = get_method_param_type(tp, i); + do_type_walk(cont, pre, post, env); + } + n_mem = get_method_n_ress(tp); + for (i = 0; i < n_mem; ++i) { + cont.typ = get_method_res_type(tp, i); + do_type_walk(cont, pre, post, env); + } + break; + + case tpo_union: + n_mem = get_union_n_members(tp); + for (i = 0; i < n_mem; ++i) { + cont.ent = get_union_member(tp, i); + do_type_walk(cont, pre, post, env); + } + break; + + case tpo_array: + cont.typ = get_array_element_type(tp); + do_type_walk(cont, pre, post, env); + cont.ent = get_array_element_entity(tp); + do_type_walk(cont, pre, post, env); + break; + + case tpo_enumeration: + /* a leave */ + break; + + case tpo_pointer: + cont.typ = get_pointer_points_to_type(tp); + do_type_walk(cont, pre, post, env); + break; + + case tpo_code: + case tpo_primitive: + case tpo_none: + case tpo_unknown: + /* a leave. */ + break; + case tpo_uninitialized: + assert(0 && "Faulty type"); + break; + } + break; /* end case k_type */ + + default: + printf(" *** Faulty type or entity! \n"); + break; + } + + /* execute post method */ + if (post) + post(tore, env); } -void type_walk(ir_graph *irg, - void (pre)(type_or_ent*, void*), void (post)(type_or_ent*, void*), - void *env) +/** Check whether node contains types or entities as an attribute. + If so start a walk over that information. */ +static void irn_type_walker( + ir_node *node, type_walk_func *pre, type_walk_func *post, void *env) { - /* this is needed to pass the parameters to the walker that actually - walks the type information */ - type_walk_env* type_env; - type_env = (type_walk_env *) malloc (sizeof(type_walk_env)); - type_env->pre = pre; - type_env->post = post; - type_env->env = env; + type_or_ent cont; - ++type_visited; - irg_walk(get_irg_end(irg), start_type_walk, NULL, type_env); + assert(node); - type_walk_2((type_or_ent *)get_irg_ent(irg), pre, post, env); + cont.ent = get_irn_entity_attr(node); + if (cont.ent) + do_type_walk(cont, pre, post, env); + cont.typ = get_irn_type_attr(node); + if (cont.typ) + do_type_walk(cont, pre, post, env); +} + +/** Check whether node contains types or entities as an attribute. + If so start a walk over that information. */ +static void start_type_walk(ir_node *node, void *ctx) +{ + type_walk_env *env = (type_walk_env*)ctx; + type_walk_func *pre; + type_walk_func *post; + void *envi; + + pre = env->pre; + post = env->post; + envi = env->env; + + irn_type_walker(node, pre, post, envi); +} + +void type_walk(type_walk_func *pre, type_walk_func *post, void *env) +{ + size_t i, n_types = get_irp_n_types(); + type_or_ent cont; + + irp_reserve_resources(irp, IRP_RESOURCE_TYPE_VISITED); + inc_master_type_visited(); + for (i = 0; i < n_types; ++i) { + cont.typ = get_irp_type(i); + do_type_walk(cont, pre, post, env); + } + cont.typ = get_glob_type(); + do_type_walk(cont, pre, post, env); + irp_free_resources(irp, IRP_RESOURCE_TYPE_VISITED); +} + +void type_walk_irg(ir_graph *irg, + type_walk_func *pre, + type_walk_func *post, + void *env) +{ + ir_graph *rem = current_ir_graph; + /* this is needed to pass the parameters to the walker that actually + walks the type information */ + type_walk_env type_env; + type_or_ent cont; + + type_env.pre = pre; + type_env.post = post; + type_env.env = env; + + current_ir_graph = irg; + + /* We walk over the irg to find all IR-nodes that contain an attribute + with type information. If we find one we call a type walker to + touch the reachable type information. + The same type can be referenced by several IR-nodes. To avoid + repeated visits of the same type node we must decrease the + type visited flag for each walk. This is done in start_type_walk(). + Here we initially increase the flag. We only call do_type_walk that does + not increase the flag. + */ + irp_reserve_resources(irp, IRP_RESOURCE_TYPE_VISITED); + inc_master_type_visited(); + irg_walk(get_irg_end(irg), start_type_walk, NULL, &type_env); + + cont.ent = get_irg_entity(irg); + do_type_walk(cont, pre, post, env); + + cont.typ = get_irg_frame_type(irg); + do_type_walk(cont, pre, post, env); + + current_ir_graph = rem; + irp_free_resources(irp, IRP_RESOURCE_TYPE_VISITED); +} + +static void type_walk_s2s_2(type_or_ent tore, + type_walk_func *pre, + type_walk_func *post, + void *env) +{ + type_or_ent cont; + + /* marked? */ + switch (get_kind(tore.ent)) { + case k_entity: + if (entity_visited(tore.ent)) return; + break; + case k_type: + if (type_visited(tore.typ)) return; + break; + default: + break; + } + + /* iterate */ + switch (get_kind(tore.typ)) { + case k_type: + { + ir_type *tp = tore.typ; + mark_type_visited(tp); + switch (get_type_tpop_code(tp)) { + case tpo_class: + { + size_t i, n; + + n = get_class_n_supertypes(tp); + for (i = 0; i < n; ++i) { + cont.typ = get_class_supertype(tp, i); + type_walk_s2s_2(cont, pre, post, env); + } + /* execute pre method */ + if (pre) + pre(tore, env); + + n = get_class_n_subtypes(tp); + for (i = 0; i < n; ++i) { + cont.typ = get_class_subtype(tp, i); + type_walk_s2s_2(cont, pre, post, env); + } + + /* execute post method */ + if (post) + post(tore, env); + } + break; + case tpo_struct: + case tpo_method: + case tpo_union: + case tpo_array: + case tpo_enumeration: + case tpo_pointer: + case tpo_primitive: + /* dont care */ + break; + default: + printf(" *** Faulty type! \n"); + break; + } + } break; /* end case k_type */ + case k_entity: + /* don't care */ + break; + default: + printf(" *** Faulty type or entity! \n"); + break; + } +} + +void type_walk_super2sub(type_walk_func *pre, + type_walk_func *post, + void *env) +{ + type_or_ent cont; + size_t i, n_types = get_irp_n_types(); + + irp_reserve_resources(irp, IRP_RESOURCE_TYPE_VISITED); + inc_master_type_visited(); + cont.typ = get_glob_type(); + type_walk_s2s_2(cont, pre, post, env); + for (i = 0; i < n_types; ++i) { + cont.typ = get_irp_type(i); + type_walk_s2s_2(cont, pre, post, env); + } + irp_free_resources(irp, IRP_RESOURCE_TYPE_VISITED); +} + +/*****************************************************************************/ + +static void type_walk_super_2(type_or_ent tore, type_walk_func *pre, + type_walk_func *post, void *env) +{ + type_or_ent cont; + + /* marked? */ + switch (get_kind(tore.ent)) { + case k_entity: + if (entity_visited(tore.ent)) + return; + break; + case k_type: + if (type_visited(tore.typ)) + return; + break; + default: + break; + } + + /* iterate */ + switch (get_kind(tore.typ)) { + case k_type: + { + ir_type *tp = tore.typ; + mark_type_visited(tp); + switch (get_type_tpop_code(tp)) { + case tpo_class: + { + size_t i, n; + + /* execute pre method */ + if (pre) + pre(tore, env); + + n = get_class_n_supertypes(tp); + for (i = 0; i < n; ++i) { + cont.typ = get_class_supertype(tp, i); + type_walk_super_2(cont, pre, post, env); + } + + /* execute post method */ + if (post) + post(tore, env); + } + break; + case tpo_struct: + case tpo_method: + case tpo_union: + case tpo_array: + case tpo_enumeration: + case tpo_pointer: + case tpo_primitive: + /* don't care */ + break; + default: + printf(" *** Faulty type! \n"); + break; + } + } break; /* end case k_type */ + case k_entity: + /* don't care */ + break; + default: + printf(" *** Faulty type or entity! \n"); + break; + } +} + +void type_walk_super(type_walk_func *pre, type_walk_func *post, void *env) +{ + size_t i, n_types = get_irp_n_types(); + type_or_ent cont; + + irp_reserve_resources(irp, IRP_RESOURCE_TYPE_VISITED); + inc_master_type_visited(); + cont.typ = get_glob_type(); + type_walk_super_2(cont, pre, post, env); + for (i = 0; i < n_types; ++i) { + cont.typ = get_irp_type(i); + type_walk_super_2(cont, pre, post, env); + } + irp_free_resources(irp, IRP_RESOURCE_TYPE_VISITED); +} + +/*****************************************************************************/ + + +static void class_walk_s2s_2(ir_type *tp, class_walk_func *pre, + class_walk_func *post, void *env) +{ + size_t i, n; + + /* marked? */ + if (type_visited(tp)) return; + + /* Assure all supertypes are visited before */ + n = get_class_n_supertypes(tp); + for (i = 0; i < n; ++i) { + if (type_not_visited(get_class_supertype(tp, i))) + return; + } + + mark_type_visited(tp); + + /* execute pre method */ + if (pre) + pre(tp, env); + + n = get_class_n_subtypes(tp); + for (i = 0; i < n; ++i) { + class_walk_s2s_2(get_class_subtype(tp, i), pre, post, env); + } + /* execute post method */ + if (post) + post(tp, env); +} + +void class_walk_super2sub(class_walk_func *pre, + class_walk_func *post, + void *env) +{ + size_t i, n_types = get_irp_n_types(); + ir_type *tp; + + irp_reserve_resources(irp, IRP_RESOURCE_TYPE_VISITED); + inc_master_type_visited(); + for (i = 0; i < n_types; i++) { + tp = get_irp_type(i); + if (is_Class_type(tp) && + (get_class_n_supertypes(tp) == 0) && + type_not_visited(tp) && + (! is_frame_type(tp)) && + (tp != get_glob_type())) { + class_walk_s2s_2(tp, pre, post, env); + } + } + irp_free_resources(irp, IRP_RESOURCE_TYPE_VISITED); +} + + +void walk_types_entities(ir_type *tp, + entity_walk_func *doit, + void *env) +{ + size_t i, n; - return; + switch (get_type_tpop_code(tp)) { + case tpo_class: + n = get_class_n_members(tp); + for (i = 0; i < n; ++i) + doit(get_class_member(tp, i), env); + break; + case tpo_struct: + n = get_struct_n_members(tp); + for (i = 0; i < n; ++i) + doit(get_struct_member(tp, i), env); + break; + case tpo_union: + n = get_union_n_members(tp); + for (i = 0; i < n; ++i) + doit(get_union_member(tp, i), env); + break; + case tpo_array: + doit(get_array_element_entity(tp), env); + break; + case tpo_method: + case tpo_enumeration: + case tpo_pointer: + case tpo_primitive: + default: + break; + } }