2008年11月27日木曜日

関数呼び出しを埋め込む

GCC は -finstrument-functions で任意のプロファイル関数を関数の enter/return 場所に仕込むことができる。

Graphvizによるファンクション・コールの視覚化

ちなみに、このプロファイル関数 (__cyg_profile_function_enter/exit()) は決め打ちで埋め込まれるので、C++ の場合は extern "C" で宣言しなければならない。

How to use '-finstrument-functions' in C++ programs ?

この機能の実装は、単に関数呼び出しの RTX を直接展開することで行われているようだ。

[tree-ssa][rfc] -finstrument-functions at tree level

gcc-4.3.2/gcc/builtins.c
  1. static rtx  
  2. expand_builtin_profile_func (bool exitp)  
  3. {  
  4.  rtx this, which;  
  5.   
  6.  this = DECL_RTL (current_function_decl);  
  7.  gcc_assert (MEM_P (this));  
  8.  this = XEXP (this, 0);  
  9.   
  10.  if (exitp)  
  11.    which = profile_function_exit_libfunc;  
  12.  else  
  13.    which = profile_function_entry_libfunc;  
  14.   
  15.  emit_library_call (which, LCT_NORMAL, VOIDmode, 2, this, Pmode,  
  16.        expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,  
  17.        0),  
  18.        Pmode);  
  19.   
  20.  return const0_rtx;  
  21. }  

gcc-4.3.2/gcc/libfuncs.h
  1. #define profile_function_exit_libfunc (libfunc_table[LTI_profile_function_exit])  

gcc-4.3.2/gcc/optabs.c
  1. rtx libfunc_table[LTI_MAX];  

  1. rtx  
  2. init_one_libfunc (const char *name)  
  3. {  
  4.  rtx symbol;  
  5.   
  6.  /* Create a FUNCTION_DECL that can be passed to 
  7.     targetm.encode_section_info.  */  
  8.  /* ??? We don't have any type information except for this is 
  9.     a function.  Pretend this is "int foo()".  */  
  10.  tree decl = build_decl (FUNCTION_DECL, get_identifier (name),  
  11.      build_function_type (integer_type_node, NULL_TREE));  
  12.  DECL_ARTIFICIAL (decl) = 1;  
  13.  DECL_EXTERNAL (decl) = 1;  
  14.  TREE_PUBLIC (decl) = 1;  
  15.   
  16.  symbol = XEXP (DECL_RTL (decl), 0);  
  17.   
  18.  /* Zap the nonsensical SYMBOL_REF_DECL for this.  What we're left with 
  19.     are the flags assigned by targetm.encode_section_info.  */  
  20.  SET_SYMBOL_REF_DECL (symbol, 0);  
  21.   
  22.  return symbol;  
  23. }  

単に external でかつ artificial な関数呼び出しを作っているようだ。
  1.  abort_libfunc = init_one_libfunc ("abort");  
  2.  memcpy_libfunc = init_one_libfunc ("memcpy");  
  3.  memmove_libfunc = init_one_libfunc ("memmove");  
  4.  memcmp_libfunc = init_one_libfunc ("memcmp");  
  5.  memset_libfunc = init_one_libfunc ("memset");  
  6.  setbits_libfunc = init_one_libfunc ("__setbits");  
  7.   
  8. #ifndef DONT_USE_BUILTIN_SETJMP  
  9.  setjmp_libfunc = init_one_libfunc ("__builtin_setjmp");  
  10.  longjmp_libfunc = init_one_libfunc ("__builtin_longjmp");  
  11. #else  
  12.  setjmp_libfunc = init_one_libfunc ("setjmp");  
  13.  longjmp_libfunc = init_one_libfunc ("longjmp");  
  14. #endif  
  15.  unwind_sjlj_register_libfunc = init_one_libfunc ("_Unwind_SjLj_Register");  
  16.  unwind_sjlj_unregister_libfunc  
  17.    = init_one_libfunc ("_Unwind_SjLj_Unregister");  
  18.   
  19.  /* For function entry/exit instrumentation.  */  
  20.  profile_function_entry_libfunc  
  21.    = init_one_libfunc ("__cyg_profile_func_enter");  
  22.  profile_function_exit_libfunc  
  23.    = init_one_libfunc ("__cyg_profile_func_exit");  
  24.   
  25.  gcov_flush_libfunc = init_one_libfunc ("__gcov_flush");  

gcc-4.3.2/gcc/calls.h
  1. /* Output a library call to function FUN (a SYMBOL_REF rtx) 
  2.    (emitting the queue unless NO_QUEUE is nonzero), 
  3.    for a value of mode OUTMODE, 
  4.    with NARGS different arguments, passed as alternating rtx values 
  5.    and machine_modes to convert them to. 
  6.  
  7.    FN_TYPE should be LCT_NORMAL for `normal' calls, LCT_CONST for `const' 
  8.    calls, LCT_PURE for `pure' calls, LCT_CONST_MAKE_BLOCK for `const' calls 
  9.    which should be enclosed in REG_LIBCALL/REG_RETVAL notes, 
  10.    LCT_PURE_MAKE_BLOCK for `purep' calls which should be enclosed in 
  11.    REG_LIBCALL/REG_RETVAL notes with extra (use (memory (scratch)), 
  12.    or other LCT_ value for other types of library calls.  */  
  13.   
  14. void  
  15. emit_library_call (rtx orgfun, enum libcall_type fn_type,  
  16.      enum machine_mode outmode, int nargs, ...)  
  17. {  
  18.   va_list p;  
  19.   
  20.   va_start (p, nargs);  
  21.   emit_library_call_value_1 (0, orgfun, NULL_RTX, fn_type, outmode, nargs, p);  
  22.   va_end (p);  
  23. }  

同ファイル内の emit_library_call_value_1 は非常に巨大。

0 件のコメント: