Supports static inline advice functions.
authorJustin Seyster <jseyster@cs.sunysb.edu>
Tue, 31 Jul 2012 21:18:35 +0000 (17:18 -0400)
committerJustin Seyster <jseyster@cs.sunysb.edu>
Tue, 31 Jul 2012 21:18:35 +0000 (17:18 -0400)
src/aop-main.c
src/aop-pc-assign.c
src/aop-weave.c
src/aop-weave.h

index 5277bab538731c8409bf8bcb3b07086af3675406..fb866b2f8c5f809334cf7d1c10ec343ae5d92840 100644 (file)
@@ -225,6 +225,13 @@ register_plugin_attributes(void *event_data, void *data)
   register_attribute_once(&noinstr_attr);
 }
 
+static void
+remember_function_decl_pass(void *event_data, void *data)
+{
+  tree fndecl = (tree)event_data;
+  remember_function_decl(fndecl);
+}
+
 /* This pass gets called before any passes that the client plug-in
    registers.  It's here for any administrative details that need to
    take place before the instrumentation passes can execute. */
@@ -438,13 +445,17 @@ plugin_init (struct plugin_name_args *plugin_info,
   plugin_argc = plugin_info->argc;
   plugin_argv = plugin_info->argv;
 
-  /* Initialization for aop-type.c and aop-header.c. */
+  /* Initialization for aop-type.c, aop-header.c, and aop-weave.c. */
   init_type_table ();
   init_prototype_table ();
+  init_static_inline_table ();
 
   /* Register attributes. */
   register_callback(aop_plugin_name, PLUGIN_ATTRIBUTES, register_plugin_attributes, NULL);
 
+  /* Register ctree pass. */
+  register_callback(aop_plugin_name, PLUGIN_PRE_GENERICIZE, remember_function_decl_pass, NULL);
+
   /* Register our cleanup function. */
   register_callback (aop_plugin_name, PLUGIN_FINISH, aop_cleanup, NULL);
 
index 39ef293d68af74f1e8d9a772aee011e8134e5d06..6f97d21ee81742abee212ec14c05d555764282a7 100644 (file)
@@ -291,6 +291,8 @@ op_prepare_assign (struct aop_joinpoint *jp)
 
   /* Insert the new assignment. */
   new_assign = gimple_build_assign (real_lhs, tmp_lhs);
+  gimple_set_block (new_assign, gimple_block (jp->stmt));
+
   gsi_insert_after (jp->gsi, new_assign, GSI_NEW_STMT);
   jp->stmt = new_assign;
 }
index 1fe50bbe42eb9805424135e791a55650fc496c4a..28a4c53d82747875cf19244518b7240fa951aee6 100644 (file)
@@ -40,6 +40,7 @@
 #include <coretypes.h>
 #include <tm.h>
 #include <tree.h>
+#include <c-common.h>
 #include <gimple.h>
 #include <tree-flow.h>
 
@@ -110,6 +111,62 @@ is_stmt_advice (gimple stmt)
   return (slot != NULL);
 }
 
+/* This table holds the decl for every static inline we enocunter.  We
+   want to remember these decls in case they get inserted as advice,
+   in which case we need the original decl so that GCC can perform the
+   inlining. 
+
+   NB: At allocation, we store this on the heap (i.e., not in garbage
+   collected memory) because it doesn't get freed then reallocated
+   between passes.  */
+static htab_t static_inline_decls = NULL;
+
+static hashval_t
+hash_decl_by_name (const void *entry)
+{
+  tree decl = (tree)entry;
+  const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
+
+  return htab_hash_string (name);
+}
+
+static int
+hash_decl_name_eq (const void *entry1, const void *entry2)
+{
+  tree decl1 = (tree)entry1;
+  tree decl2 = (tree)entry2;
+
+  const char *name1 = IDENTIFIER_POINTER (DECL_NAME (decl1));
+  const char *name2 = IDENTIFIER_POINTER (DECL_NAME (decl2));
+
+  return (strcmp (name1, name2) == 0);
+}
+
+void
+init_static_inline_table ()
+{
+  static_inline_decls = htab_create (10, hash_decl_by_name, hash_decl_name_eq, NULL);
+}
+
+void
+free_static_inline_table ()
+{
+  htab_delete (static_inline_decls);
+}
+
+void
+remember_function_decl(tree fndecl)
+{
+  /* Check if this is a static inline function. */
+  if (DECL_DECLARED_INLINE_P(fndecl) && !TREE_PUBLIC(fndecl))
+    {
+      tree *slot;
+
+      slot = (tree *)htab_find_slot (static_inline_decls, fndecl, INSERT);
+      *slot = fndecl;
+    }
+}
+
 /* Throw a fatal error if a dynval is not allowed in a before-advice
    call. */
 static void
@@ -252,7 +309,7 @@ build_dynval (struct aop_dynval *dv, VEC(gimple, heap) *pre_stmts)
    The new nodes get stored in arglist.  GIMPLE statements that must
    be inserted before the call are put in the pre_stmts list. */
 static gimple
-build_gcc_call (const char *func_name, tree return_type,
+build_gcc_call (const char *func_name, tree return_type, tree block,
                enum aop_insert_location location, VEC(gimple, heap) *pre_stmts,
                va_list argp)
 {
@@ -262,6 +319,7 @@ build_gcc_call (const char *func_name, tree return_type,
 
   tree func_type;
   tree func_decl;
+  tree inline_decl;
   gimple func_call;
 
   arg_list = VEC_alloc (tree, heap, 2);
@@ -334,8 +392,20 @@ build_gcc_call (const char *func_name, tree return_type,
 
   func_type = build_function_type (return_type, argtype_list);
   func_decl = build_fn_decl (func_name, func_type);
+
+  /* Wait, have we encountered a static inline decl with this same
+     name? */
+  inline_decl = htab_find(static_inline_decls, func_decl);
+  if (inline_decl != NULL)
+    func_decl = inline_decl;
+
   func_call = gimple_build_call_vec (func_decl, arg_list);
 
+  /* GCC caveat, if there's a chance this call will be inlined, make
+     sure it has a block. */
+  if (func_decl == inline_decl)
+    gimple_set_block(func_call, block);
+
   VEC_free (tree, heap, arg_list);
 
   remember_advice (func_call);
@@ -400,6 +470,7 @@ aop_insert_advice (struct aop_joinpoint *jp, const char *func_name,
   va_list argp;
   gimple func_call;
   struct aop_pointcut *pc;
+  tree block = NULL;
   VEC(gimple, heap) *pre_stmts;
 
   pc = jp->pc;
@@ -411,11 +482,14 @@ aop_insert_advice (struct aop_joinpoint *jp, const char *func_name,
       jp->is_prepared = true;
     }
 
+  if (jp->stmt != NULL)
+    block = gimple_block(jp->stmt);
+
   pre_stmts = VEC_alloc (gimple, heap, 2);
 
   va_start (argp, location);
-  func_call = build_gcc_call (func_name, void_type_node, location, pre_stmts,
-                             argp);
+  func_call = build_gcc_call (func_name, void_type_node, block, location,
+                             pre_stmts, argp);
   va_end (argp);
 
   va_start (argp, location);
@@ -511,6 +585,7 @@ aop_duplicate (struct aop_joinpoint *jp, const char *func_name, ...)
 {
   va_list argp;
   gimple func_call;
+  tree block = NULL;
   struct aop_pointcut *pc;
   VEC(gimple, heap) *pre_stmts;
 
@@ -525,11 +600,14 @@ aop_duplicate (struct aop_joinpoint *jp, const char *func_name, ...)
   else if (is_current_func_duplicated())
     fatal_error ("(InterAspect) Cannot duplicate a function more than once.");
 
+  if (jp->stmt != NULL)
+    block = gimple_block(jp->stmt);
+
   pre_stmts = VEC_alloc (gimple, heap, 2);
 
   va_start (argp, func_name);
-  func_call = build_gcc_call (func_name, integer_type_node, AOP_INSERT_BEFORE,
-                             pre_stmts, argp);
+  func_call = build_gcc_call (func_name, integer_type_node, block,
+                             AOP_INSERT_BEFORE, pre_stmts, argp);
   va_end (argp);
 
   va_start (argp, func_name);
index 98f4da6fe5aba085243d6b7257489e3fa0b4a61d..113f4a03d0a7f05ef10663bfbcecf966bd4cf5db 100644 (file)
@@ -31,4 +31,8 @@
 extern void clear_advice_table ();
 extern bool is_stmt_advice (gimple stmt);
 
+extern void init_static_inline_table ();
+extern void free_static_inline_table ();
+extern void remember_function_decl (tree fndecl);
+
 #endif