From: Michael Beck Date: Mon, 24 Oct 2005 14:11:02 +0000 (+0000) Subject: a simple analysys which determines which pointer arguments are read/write X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=ff250a974bfc97f7a9acf86ad77bbfaed855cb04;p=libfirm a simple analysys which determines which pointer arguments are read/write [r6793] --- diff --git a/ir/ana/Makefile.in b/ir/ana/Makefile.in index a2a4faf55..cbb1fe4ca 100644 --- a/ir/ana/Makefile.in +++ b/ir/ana/Makefile.in @@ -17,7 +17,8 @@ subdir := ir/ana INSTALL_HEADERS = irouts.h trouts.h irdom.h cgana.h irloop.h irtypeinfo.h irsimpletype.h \ callgraph.h rta.h interval_analysis.h \ - field_temperature.h execution_frequency.h irextbb.h irconsconfirm.h + field_temperature.h execution_frequency.h irextbb.h irconsconfirm.h \ + analyze_irg_args.h SOURCES = $(INSTALL_HEADERS) @@ -26,7 +27,7 @@ SOURCES += Makefile.in \ irloop_t.h irbackedge.c irbackedge_t.h irscc.c ircfscc.c \ irtypeinfo.c irsimpletype.c interval_analysis.c \ callgraph.c field_temperature.c execution_frequency.c phiclass.c \ - irextbb.c irextbb_t.h irconsconfirm.c + irextbb.c irextbb_t.h irconsconfirm.c analyze_irg_args.c include $(topdir)/MakeRules diff --git a/ir/ana/analyze_irg_args.c b/ir/ana/analyze_irg_args.c new file mode 100644 index 000000000..50f981e89 --- /dev/null +++ b/ir/ana/analyze_irg_args.c @@ -0,0 +1,274 @@ +/* + * Project: libFIRM + * File name: ir/ana/analyze_irg_agrs.c + * Purpose: read/write analyze of graph argument, which have mode reference. + * Author: Beyhan Veliev + * Created: + * CVS-ID: $Id$ + * Copyright: (c) 1998-2005 Universität Karlsruhe + * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE. + */ + +/** + * @file analyze_irg_agrs.c + * + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_MALLOC_H +#include +#endif +#ifdef HAVE_ALLOCA_H +#include +#endif +#include + +#include "irouts.h" +#include "irnode_t.h" +#include "irmode_t.h" +#include "array.h" +#include "irprog.h" +#include "entity_t.h" + +#include "analyze_irg_args.h" + +/** + * A struct to save if a graph argument with mode reference is + * read/write or both. + */ +typedef struct { + unsigned char read; + unsigned char write; +} rw_info_t; + +enum access { + ACC_UNKNOWN, + ACC_ACCESSED, + ACC_NOT_ACCESSED +}; + +#define ACCESS(a) if ((a) == ACC_UNKNOWN) (a) = ACC_ACCESSED +#define NOT_ACCESS(a) if ((a) == ACC_UNKNOWN) (a) = ACC_NOT_ACCESSED + +static char v; +static void *VISITED = &v; + +/** + * Walk recursive the successors of a graph argument + * with mode reference and mark in the "irg_args" if it will be read, + * written or both. + * + * @param arg The graph argument with mode reference, + * that must be checked. + */ +static unsigned analyze_arg(ir_node *arg, unsigned bits) +{ + int i, p; + ir_node *succ; + + /* We must visit a node once to avoid endless recursion.*/ + set_irn_link(arg, VISITED); + + for (i = get_irn_n_outs(arg) - 1; i >= 0; --i) { + succ = get_irn_out(arg, i); + + /* We was here.*/ + if (get_irn_link(succ) == VISITED) + continue; + + /* We should not walk over the memory edge.*/ + if (get_irn_mode(succ) == mode_M) + continue; + + /* A addition or subtraction of the argument with output, that + isn't with mode reference must not be checked.*/ + if ((get_irn_op(succ) == op_Add || get_irn_op(succ) == op_Sub) && + !mode_is_reference(get_irn_mode(succ))) + continue; + + /* A Block as successor isn't interesting.*/ + if (get_irn_op(succ) == op_Block) + continue; + + /* If we reach with the recursion a Call node and our reference + isn't the address of this Call we accept that the reference will + be read and written if the graph of the method represented by + "Call" isn't computed else we analyze that graph. If our + reference is the address of this + Call node that mean the reference will be read.*/ + if (get_irn_op(succ) == op_Call) { + ir_node *Call_ptr = get_Call_ptr(succ); + + if (Call_ptr == arg) + return bits | ptr_access_read; + else if (op_SymConst == get_irn_op(Call_ptr) && + get_SymConst_kind(Call_ptr) == symconst_addr_ent) { + entity *meth_ent = get_SymConst_entity(Call_ptr); + + for (p = get_Call_n_params(succ) - 1; p >= 0; --p){ + if (get_Call_param(succ, p) == arg) { + /* an arg can be used more than once ! */ + bits |= get_method_param_access(meth_ent, p); + } + } + } else + bits |= ptr_access_rw; + } + else if (get_irn_op(succ) == op_Store) { + /* We have reached a Store node => the reference is written. */ + bits |= ptr_access_write; + } + else if (get_irn_op(succ) == op_Load) { + /* We have reached a Load node => the reference is read. */ + bits |= ptr_access_read; + } + + /* If we know that, the argument will be read and written, we + can break the recursion.*/ + if (bits == ptr_access_rw) + return ptr_access_rw; + + bits = analyze_arg(succ, bits); + } + set_irn_link(arg, NULL); + return bits; +} + + +/** + * Check if a argument of the ir graph with mode + * reference is read, write or both. + * + * @param irg The ir graph to analyze. + */ +static void analyze_ent_args(entity *ent) +{ + ir_graph *irg; + ir_node *irg_args, *arg; + ir_mode *arg_mode; + int nparams, i; + long proj_nr; + type *mtp; + unsigned bits; + rw_info_t *rw_info; + + mtp = get_entity_type(ent); + nparams = get_method_n_params(mtp); + + ent->param_access = NEW_ARR_F(ptr_access_kind, nparams); + + /* If the method haven't parameters we have + * nothing to do.*/ + if (nparams <= 0) + return; + + irg = get_entity_irg(ent); + + if (! irg) { + /* if we could not determine the graph, set RW access */ + for (i = nparams - 1; i >= 0; --i) + ent->param_access[i] = + is_Pointer_type(get_method_param_type(mtp, i)) ? ptr_access_rw : ptr_access_none; + + return; + } + + /* Call algorithm that computes the out edges */ + if (get_irg_outs_state(irg) != outs_consistent) + compute_outs(irg); + + irg_args = get_irg_args(irg); + + /* A array to save the information for each argument with + mode reference.*/ + NEW_ARR_A(rw_info_t, rw_info, nparams); + + /* We initialize the element with UNKNOWN state. */ + for (i = nparams - 1; i >= 0; --i) { + rw_info[i].read = ACC_UNKNOWN; + rw_info[i].write = ACC_UNKNOWN; + } + + /* search for arguments with mode reference + to analyze them.*/ + for (i = get_irn_n_outs(irg_args) - 1; i >= 0; --i) { + arg = get_irn_out(irg_args, i); + arg_mode = get_irn_mode(arg); + proj_nr = get_Proj_proj(arg); + + if (mode_is_reference(arg_mode)) { + bits = analyze_arg(arg, ptr_access_none); + + if (bits & ptr_access_read) + ACCESS(rw_info[proj_nr].read); + if (bits & ptr_access_write) + ACCESS(rw_info[proj_nr].write); + } + } + + /* set all unknown values to NOT_ACCESSED */ + for (i = nparams - 1; i >= 0; --i) { + NOT_ACCESS(rw_info[i].read); + NOT_ACCESS(rw_info[i].write); + + ent->param_access[i] = (rw_info[i].read == ACC_ACCESSED ? ptr_access_read : ptr_access_none) | + (rw_info[i].write == ACC_ACCESSED ? ptr_access_write : ptr_access_none); + } + + printf("%s:\n", get_entity_name(ent)); + for (i = 0; i < nparams; ++i) { + if (is_Pointer_type(get_method_param_type(mtp, i))) + printf("Pointer Arg %i wird %s %s\n", i, + ent->param_access[i] & ptr_access_read ? "gelesen" : "", + ent->param_access[i] & ptr_access_write ? "geschrieben" : ""); + } +} + +/* + * Compute for a method with pointer parameter(s) + * if they will be read or written. + */ +ptr_access_kind get_method_param_access(entity *ent, int pos) +{ + type *mtp = get_entity_type(ent); + int is_variadic = get_method_variadicity(mtp) == variadicity_variadic; + + assert(0 <= pos && (is_variadic || pos < get_method_n_params(mtp))); + + if (ent->param_access) { + if (pos < ARR_LEN(ent->param_access)) + return ent->param_access[pos]; + else + return ptr_access_rw; + } + + analyze_ent_args(ent); + + if (pos < ARR_LEN(ent->param_access)) + return ent->param_access[pos]; + else + return ptr_access_rw; +} + +/** + * Analyze how pointer arguments of a given + * ir graph are accessed. + * + * @param irg The ir graph to analyze. + */ +void analyze_irg_args(ir_graph *irg) +{ + entity *ent; + + if (irg == get_const_code_irg()) + return; + + ent = get_irg_entity(irg); + if (! ent) + return; + + if (! ent->param_access) + analyze_ent_args(ent); +} diff --git a/ir/ana/analyze_irg_args.h b/ir/ana/analyze_irg_args.h new file mode 100644 index 000000000..dda9e6fcc --- /dev/null +++ b/ir/ana/analyze_irg_args.h @@ -0,0 +1,38 @@ +/* + * Project: libFIRM + * File name: ir/ana/analyze_irg_args.h + * Purpose: rea/write analyze of graph argument, which have mode reference. + * Author: Beyhan Veliev + * Created: + * CVS-ID: $Id$ + * Copyright: (c) 1998-2005 Universität Karlsruhe + * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE. + */ +#ifndef _ANALYZE_IRG_ARGS_H_ +#define _ANALYZE_IRG_ARGS_H_ + +#include "irgraph.h" +#include "entity.h" + +/** + * Returns for a method with pointer parameter + * if they will be read or written. + * + * @param ent The entity that represent this method. + * @param pos The position of method's parameter for that + * we need information. + + * If the pos'th parameter is NOT of a pointer type, ptr_access_none + * is returned; + */ +ptr_access_kind get_method_param_access(entity *ent, int pos); + +/** + * Analyze how pointer arguments of a given + * ir graph are accessed. + * + * @param irg The ir graph to analyze. + */ +void analyze_irg_args(ir_graph *irg); + +#endif /*_ANALYZE_IRG_ARGS_H_ */