From: Justin Seyster Date: Wed, 11 Aug 2010 23:41:13 +0000 (-0400) Subject: Added support for duplicating a function. X-Git-Tag: release-v1.0~73^2~7 X-Git-Url: https://git.fsl.cs.stonybrook.edu/?a=commitdiff_plain;h=7186e24de468a37e07935cdee17316577a52e8b3;p=interaspect.git Added support for duplicating a function. --- diff --git a/src/Makefile.am b/src/Makefile.am index 7102bdf..0c6c3d2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,7 @@ lib_LTLIBRARIES = libinteraspect.la -libinteraspect_la_SOURCES = aop-pc-assign.c aop-main.c aop-type.c aop-weave.c aop-pc-entry.c aop-pc-exit.c aop-pc-fun-call.c aop-pointcut.c +libinteraspect_la_SOURCES = aop-pc-assign.c aop-main.c aop-type.c aop-weave.c \ + aop-pc-entry.c aop-pc-exit.c aop-pc-fun-call.c aop-pointcut.c \ + aop-duplicate.c libinteraspect_la_CFLAGS = -Wall -Werror -fvisibility=hidden -prefer-pic libinteraspect_la_LDFLAGS = -static -prefer-pic -version-info 1:0:0 libinteraspect_la_CPPFLAGS = -DHAVE_CONFIG_H -DIN_GCC -I$(gcc_includes) diff --git a/src/aop-duplicate.c b/src/aop-duplicate.c new file mode 100644 index 0000000..b7d19bd --- /dev/null +++ b/src/aop-duplicate.c @@ -0,0 +1,308 @@ +/* This program is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* Whether we want them or not (we don't), Autoconf _insists_ on + defining these. Since GCC's config.h (which we must include) also + defines them, we have to undef them here. */ +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aop.h" +#include "aop-duplicate.h" + +typedef struct label_pair { + tree old; + tree new; +} label_pair; + +#define INITIAL_PAIRS 10 + +/* TODO: This needs to be garbage collected. */ +DEF_VEC_O(label_pair); +DEF_VEC_ALLOC_O(label_pair, heap); + +#define FOR_EACH_BB_PAIR(pairs, index, pair) \ + for ((index)=0; VEC_iterate(bb_pair, pairs, index, pair); (index)++) + +#define FOR_EACH_LABEL_PAIR(pairs, index, pair) \ + for ((index)=0; VEC_iterate(label_pair, pairs, index, pair); (index)++) + +static basic_block +new_bb_for_old(VEC(bb_pair, gc) *bb_pairs, basic_block old) +{ + unsigned int pair_index; + bb_pair *pair; + + FOR_EACH_BB_PAIR(bb_pairs, pair_index, pair) + { + if (pair->old == old) + return pair->new; + } + + return NULL; +} + +static tree +label_new_for_old(VEC(label_pair, heap) *label_pairs, tree old) +{ + unsigned int pair_index; + label_pair *pair; + + FOR_EACH_LABEL_PAIR(label_pairs, pair_index, pair) + if (pair->old == old) + return pair->new; + + return NULL; +} + +static tree +fix_labels(tree *label, int *walk_subtrees, void *arg) +{ + struct walk_stmt_info *wi = (struct walk_stmt_info*) arg; + + if (TREE_CODE(*label) == LABEL_DECL) + { + tree new_label; + VEC(label_pair, heap) *label_pairs; + + label_pairs = (VEC(label_pair, heap) *)(wi->info); + new_label = label_new_for_old(label_pairs, *label); + + aop_assert (new_label != NULL_TREE); + *label = new_label; + } + + return NULL_TREE; +} + +/* This function makes another copy of function body (blocks except entry + and exit along with their topology). This function also adds a distributor + block to direct to 2 bodies. The distributor block is like the following: + + 1 int tmpvar; + 2 tmpvar = call(); + 3 if (tmpvar != 0) + 4 goto + 5 else + 6 goto ; + + If call is NULL, line 2 is replaced by tmpvar = 0. Then it is the user's + duty to further populate the distributor block. + */ +void +duplicate_function_body (VEC(bb_pair, gc) **bb_pairs_ptr, + basic_block *distributor_bb_ptr, + const char *tmpvar_name, gimple call) +{ + VEC(bb_pair, gc) *bb_pairs; + VEC(label_pair, heap) *label_pairs; + + unsigned int pair_index; + bb_pair *pair_p; + + basic_block cur_bb; + basic_block last_bb; + + bb_pairs = VEC_alloc (bb_pair, gc, INITIAL_PAIRS); + label_pairs = VEC_alloc (label_pair, heap, INITIAL_PAIRS); + + /* Pass 1 - Collect a list of all the blocks that need duplication. */ + FOR_EACH_BB (cur_bb) + { + if (can_duplicate_block_p (cur_bb)) + { + bb_pair bbpair; + bbpair.old = cur_bb; + bbpair.new = NULL; + VEC_safe_push (bb_pair, gc, bb_pairs, &bbpair); + } + else + { + /* As of writing, only the entry and exit blocks cannot be + duplicated. */ + aop_assert (cur_bb == EXIT_BLOCK_PTR || cur_bb == ENTRY_BLOCK_PTR); + } + } + + /* Pass 2 - Duplicate the blocks in the list. Refer to copy_bbs() + in cfglayout.c. */ + initialize_original_copy_tables (); + last_bb = EXIT_BLOCK_PTR->prev_bb; + + FOR_EACH_BB_PAIR (bb_pairs, pair_index, pair_p) + { + gimple old_first_stmt; + + pair_p->new = duplicate_block (pair_p->old, NULL, last_bb); + last_bb = pair_p->new; + + old_first_stmt = first_stmt (pair_p->old); + aop_assert (old_first_stmt != NULL); + + /* duplicate_block() does not copy initial labels. Calling + gimple_block_label() on the duplicated block will create the + label for us. */ + if (gimple_code (old_first_stmt) == GIMPLE_LABEL) + { + label_pair lblpair; + lblpair.old = gimple_block_label (pair_p->old); + lblpair.new = gimple_block_label (pair_p->new); + DECL_SOURCE_LOCATION (lblpair.new) = DECL_SOURCE_LOCATION (lblpair.old); + VEC_safe_push (label_pair, heap, label_pairs, &lblpair); + } + } + + /* Pass 3 - Fix all edges in the duplicate blocks and correct label + references. */ + FOR_EACH_BB_PAIR (bb_pairs, pair_index, pair_p) + { + edge_iterator ei; + edge e; + gimple_stmt_iterator gsi; + struct walk_stmt_info wi; + + /* Skip over initial label statements, which we want to leave + alone. */ + gsi = gsi_start_bb (pair_p->new); + while (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL) + { + gsi_next (&gsi); + } + gcc_assert(!gsi_end_p(gsi)); + + for (; !gsi_end_p (gsi); gsi_next (&gsi)) + { + memset (&wi, 0, sizeof (wi)); + wi.info = (struct walk_stmt_info *)label_pairs; + walk_gimple_stmt (&gsi, NULL, fix_labels, &wi); + } + + FOR_EACH_EDGE (e, ei, pair_p->new->succs) + { + basic_block succ_bb = e->dest; + + if (can_duplicate_block_p(succ_bb)) + { + basic_block new_bb; + edge redirected_edge; + + new_bb = new_bb_for_old (bb_pairs, succ_bb); + aop_assert (new_bb != NULL); + + redirected_edge = redirect_edge_and_branch (e, new_bb); + aop_assert (redirected_edge != NULL); + } + } + } + + /* Pass 4 - Create the distributor block and bind it up */ + { + edge e; + + basic_block old_first_bb; + basic_block new_first_bb; + basic_block distributor_bb; + + tree old_label; + tree new_label; + tree tmpvar; + + gimple cond; + gimple_stmt_iterator gsi; + + e = single_succ_edge (ENTRY_BLOCK_PTR); + + old_first_bb = e->dest; + new_first_bb = new_bb_for_old (bb_pairs, old_first_bb); + aop_assert (new_first_bb != NULL); + + old_label = gimple_block_label (old_first_bb); + new_label = gimple_block_label (new_first_bb); + + /* TODO: Can this line be removed? */ + DECL_SOURCE_LOCATION(new_label) = DECL_SOURCE_LOCATION(old_label); + distributor_bb = split_edge(e); + + tmpvar = create_tmp_var(integer_type_node, tmpvar_name); + /*add_referenced_var(tmpvar);*/ + + gsi = gsi_start_bb (distributor_bb); + if (call == NULL) + { + /* insert: tmpvar = 0; */ + gimple assign; + assign = + gimple_build_assign_with_ops (NOP_EXPR, tmpvar, + build_int_cst (integer_type_node, 0), + NULL_TREE); + + /* TODO: Do we need this? */ + if (gimple_in_ssa_p (cfun)) + { + tmpvar = make_ssa_name (tmpvar, assign); + gimple_assign_set_lhs (assign, tmpvar); + } + gsi_insert_before (&gsi, assign, GSI_SAME_STMT); + } + else + { + /* insert: tmpvar = distributor_fn(...) */ + /* TODO: No need to copy. */ + gimple distributor_fn = gimple_copy(call); + aop_assert (gimple_code (distributor_fn) == GIMPLE_CALL); + + /* TODO: Do we need this? */ + if (gimple_in_ssa_p (cfun)) + { + tmpvar = make_ssa_name (tmpvar, distributor_fn); + } + gimple_call_set_lhs (distributor_fn, tmpvar); + gsi_insert_before (&gsi, distributor_fn, GSI_SAME_STMT); + } + + /* insert: if (tmpvar) goto else goto */ + cond = gimple_build_cond (NE_EXPR, tmpvar, + build_int_cst (integer_type_node, 0), + new_label, old_label); + gsi_insert_before (&gsi, cond, GSI_SAME_STMT); + + remove_edge(single_succ_edge(distributor_bb)); + make_edge(distributor_bb, old_first_bb, EDGE_FALSE_VALUE); + make_edge(distributor_bb, new_first_bb, EDGE_TRUE_VALUE); + + *distributor_bb_ptr = distributor_bb; + } + + *bb_pairs_ptr = bb_pairs; + + free_original_copy_tables(); + VEC_free (label_pair, heap, label_pairs); + return; +} diff --git a/src/aop-duplicate.h b/src/aop-duplicate.h new file mode 100644 index 0000000..878a549 --- /dev/null +++ b/src/aop-duplicate.h @@ -0,0 +1,33 @@ +#ifndef __AOP_DUPLICATE_H__ +#define __AOP_DUPLICATE_H__ + +/* This program is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* This is a private header. Do not include it in source files for + client plug-ins. */ + +typedef struct bb_pair { + basic_block old; + basic_block new; +} bb_pair; + +DEF_VEC_O(bb_pair); +DEF_VEC_ALLOC_O(bb_pair, gc); + +extern void duplicate_function_body (VEC(bb_pair, gc) **bb_pairs_ptr, + basic_block *distributor_bb_ptr, + const char *tmpvar_name, gimple call); + +#endif diff --git a/src/aop-weave.c b/src/aop-weave.c index 4928666..2f84133 100644 --- a/src/aop-weave.c +++ b/src/aop-weave.c @@ -40,6 +40,7 @@ #undef GENERATOR_FILE #include "aop.h" +#include "aop-duplicate.h" #include "aop-dynval.h" #include "aop-pointcut.h" @@ -262,3 +263,30 @@ aop_insert_advice (struct aop_joinpoint *jp, const char *func_name, pc->insert_after(jp, func_call); } + +void +aop_duplicate (struct aop_joinpoint *jp, const char *func_name, ...) +{ + va_list argp; + gimple func_call; + struct aop_pointcut *pc; + + VEC(bb_pair, gc) *bb_pairs; + basic_block distributor; + + pc = jp->pc; + + if (pc->kind != ATP_ENTRY) + fatal_error ("(InterAspect) Function duplication must be done on a" + " function entry join point."); + else if (jp->is_prepared) + fatal_error ("(InterAspect) Illegal to duplicate using a join point that" + " has already been used to insert advice."); + + va_start (argp, func_name); + func_call = build_gcc_call (func_name, integer_type_node, AOP_INSERT_BEFORE, + argp); + va_end (argp); + + duplicate_function_body (&bb_pairs, &distributor, "ia_body_index", func_call); +} diff --git a/src/aop.h b/src/aop.h index 9e9b607..7a73d80 100644 --- a/src/aop.h +++ b/src/aop.h @@ -160,6 +160,7 @@ enum aop_insert_location { extern void aop_insert_advice (struct aop_joinpoint *jp, const char *name, enum aop_insert_location location, ...); +extern void aop_duplicate (struct aop_joinpoint *jp, const char *name, ...); extern const struct aop_type *aop_t_all_signed (); extern const struct aop_type *aop_t_all_unsigned ();