00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #include "defs.h"
00044 #include "wn.h"
00045 #include "wn_util.h"
00046 #include "data_layout.h"
00047 #include "config_opt.h"
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 static BOOL
00062 Do_cyg_instrument_p( ST *st_func )
00063 {
00064
00065 PU &pu = Pu_Table[ST_pu(st_func)];
00066 if ( PU_no_instrument( pu ) ) return FALSE;
00067 switch ( OPT_Cyg_Instrument ) {
00068 case 1: return ! PU_is_inline_function( pu );
00069 case 2: return ! PU_is_marked_inline( pu );
00070 case 3: return ! PU_must_inline( pu );
00071 default: break;
00072 }
00073 return TRUE;
00074 }
00075
00076
00077 BOOL VHO_Cyg_Instrument_PU;
00078 static ST *VHO_return_address_st;
00079 static ST *VHO_Cyg_enter_st;
00080 static ST *VHO_Cyg_exit_st;
00081
00082
00083
00084
00085 static void
00086 CYG_Initialize_for_PU()
00087 {
00088
00089 VHO_return_address_st = Find_Special_Return_Address_Symbol();
00090
00091
00092 if ( VHO_return_address_st == NULL ) {
00093 VHO_return_address_st = New_ST( CURRENT_SYMTAB );
00094 ST_Init( VHO_return_address_st, Save_Str( "__return_address" ), CLASS_VAR,
00095 ( PUSH_RETURN_ADDRESS_ON_STACK ? SCLASS_FORMAL : SCLASS_AUTO ),
00096 EXPORT_LOCAL, MTYPE_To_TY(Pointer_Mtype) );
00097
00098 Set_PU_has_return_address( Get_Current_PU() );
00099 }
00100
00101
00102 TY_IDX ty = Make_Function_Type( MTYPE_To_TY(MTYPE_V) );
00103 VHO_Cyg_enter_st = Gen_Intrinsic_Function( ty, "__cyg_profile_func_enter" );
00104 VHO_Cyg_exit_st = Gen_Intrinsic_Function( ty, "__cyg_profile_func_exit" );
00105
00106 PU &pu_enter = Pu_Table[ST_pu( VHO_Cyg_enter_st )];
00107 Clear_PU_no_side_effects( pu_enter );
00108 Clear_PU_is_pure( pu_enter );
00109 Set_PU_no_delete( pu_enter );
00110
00111 PU &pu_exit = Pu_Table[ST_pu( VHO_Cyg_exit_st )];
00112 Clear_PU_no_side_effects( pu_exit );
00113 Clear_PU_is_pure( pu_exit );
00114 Set_PU_no_delete( pu_exit );
00115
00116
00117 PU &pu_cur = Get_Current_PU();
00118 Set_PU_no_inline( pu_cur );
00119 if ( PU_must_inline( pu_cur ) ) {
00120 DevWarn( "Disabling must_inline for PU %s",
00121 ST_name( Get_Current_PU_ST() ) );
00122 if ( OPT_Cyg_Instrument < 4 ) Set_PU_no_instrument( pu_cur );
00123 Clear_PU_must_inline( pu_cur );
00124 }
00125 }
00126
00127
00128 static void
00129 Generate_cyg_profile_func( BOOL is_exit, ST *st_func,
00130 LABEL_IDX exit_label, WN* wn, WN *block )
00131 {
00132
00133
00134
00135 TY_IDX ty_idx = Make_Pointer_Type( MTYPE_To_TY(MTYPE_V) );
00136
00137
00138 WN *parm0 = WN_Lda( Pointer_Mtype, (WN_OFFSET) 0, st_func, (UINT) 0 );
00139 WN *arg0 = WN_CreateParm( Pointer_Mtype, parm0, ty_idx, WN_PARM_BY_VALUE );
00140 Set_ST_addr_passed( st_func );
00141
00142
00143 WN *parm1;
00144 if ( exit_label == LABEL_IDX_ZERO ) {
00145 parm1 = WN_Ldid( Pointer_Mtype, 0, VHO_return_address_st,
00146 ST_type( VHO_return_address_st ) );
00147 } else {
00148 parm1 = WN_LdaLabel( Pointer_Mtype, exit_label );
00149 Set_LABEL_addr_saved( exit_label );
00150 }
00151 WN *arg1 = WN_CreateParm( Pointer_Mtype, parm1, ty_idx, WN_PARM_BY_VALUE );
00152
00153
00154 WN *call_wn = WN_Call( MTYPE_V, MTYPE_V, 2,
00155 is_exit ? VHO_Cyg_exit_st : VHO_Cyg_enter_st );
00156 WN_kid0( call_wn ) = arg0;
00157 WN_kid1( call_wn ) = arg1;
00158 WN_Set_Linenum( call_wn, WN_Get_Linenum(wn) );
00159 WN_Set_Call_Default_Flags( call_wn );
00160 if ( is_exit ) {
00161 WN_INSERT_BlockBefore( block, wn, call_wn );
00162 } else {
00163 WN_INSERT_BlockAfter( block, wn, call_wn );
00164 }
00165 }
00166
00167
00168
00169
00170
00171
00172
00173
00174 static void CYG_Traverse( WN *wn );
00175
00176 static WN *
00177 CYG_Instrument_Block( WN *block, WN *wn_first )
00178 {
00179 WN *wn, *wn_next, *wn_label;
00180 LABEL_IDX exit_label;
00181 BOOL do_inline_inst;
00182
00183 Is_True( WN_operator(block) == OPR_BLOCK,
00184 ( "CYG_Instrument_Block expected BLOCK block" ) );
00185
00186 for ( wn = wn_first; wn; wn = wn_next ) {
00187 wn_next = WN_next(wn);
00188
00189 OPERATOR opr = WN_operator(wn);
00190 if (! OPERATOR_is_leaf(opr)) CYG_Traverse( wn );
00191
00192 if ( opr == OPR_RETURN || opr == OPR_RETURN_VAL
00193 #ifdef KEY
00194 || opr == OPR_GOTO_OUTER_BLOCK
00195 #endif
00196 ) {
00197 if ( Do_cyg_instrument_p( Get_Current_PU_ST() ) ) {
00198 Generate_cyg_profile_func( TRUE, Get_Current_PU_ST(),
00199 LABEL_IDX_ZERO, wn, block );
00200 }
00201 } else if ( opr == OPR_PRAGMA ) {
00202
00203 switch ( WN_pragma(wn) ) {
00204
00205 case WN_PRAGMA_PREAMBLE_END:
00206 if ( Do_cyg_instrument_p( Get_Current_PU_ST() ) ) {
00207 Generate_cyg_profile_func( FALSE, Get_Current_PU_ST(),
00208 LABEL_IDX_ZERO, wn, block );
00209 }
00210 break;
00211
00212 case WN_PRAGMA_INLINE_BODY_START:
00213
00214 do_inline_inst = Do_cyg_instrument_p( WN_st(wn) );
00215 if ( do_inline_inst ) {
00216 LABEL_Init( New_LABEL( CURRENT_SYMTAB, exit_label ), 0, LKIND_TAG );
00217 Generate_cyg_profile_func( FALSE, WN_st(wn), exit_label, wn, block );
00218 }
00219
00220
00221
00222
00223 wn = CYG_Instrument_Block( block, wn_next );
00224 wn_next = WN_next( wn );
00225
00226
00227 Is_True( wn && WN_operator(wn) == OPR_PRAGMA &&
00228 WN_pragma(wn) == WN_PRAGMA_INLINE_BODY_END,
00229 ( "CYG_Instrument_Block missed INLINE_BODY_END Pragma" ) );
00230 if ( do_inline_inst ) {
00231 Generate_cyg_profile_func( TRUE, WN_st(wn), exit_label, wn, block );
00232 wn_label = WN_CreateLabel( (ST_IDX) 0, exit_label, 0, NULL );
00233 WN_Set_Linenum( wn_label, WN_Get_Linenum(wn) );
00234 WN_INSERT_BlockAfter( block, wn, wn_label );
00235 }
00236 break;
00237
00238 case WN_PRAGMA_INLINE_BODY_END:
00239 return wn;
00240
00241 default:
00242 break;
00243 }
00244 }
00245 }
00246
00247 return NULL;
00248 }
00249
00250
00251
00252 static void CYG_Traverse( WN *wn )
00253 {
00254 Is_True( WN_operator(wn) != OPR_BLOCK,
00255 ( "CYG_Traverse expected non-BLOCK wn" ) );
00256 for ( INT k = 0; k < WN_kid_count(wn); ++k ) {
00257 WN *kid = WN_kid( wn, k );
00258 if (OPERATOR_is_leaf(WN_operator(kid))) ;
00259 else if ( WN_operator(kid) == OPR_BLOCK ) {
00260 CYG_Instrument_Block( kid, WN_first(kid) );
00261 } else {
00262 CYG_Traverse(kid);
00263 }
00264 }
00265 }
00266
00267
00268 void
00269 CYG_Instrument_Driver( WN *wn_pu )
00270 {
00271 Is_True( OPT_Cyg_Instrument >= 1,
00272 ( "CYG_Instrument_Driver should not have been invoked." ) );
00273 CYG_Initialize_for_PU();
00274
00275
00276
00277 WN *wn_body, *wn_last, *wn_return;
00278 if ( WN_operator(wn_pu) == OPR_FUNC_ENTRY &&
00279 ( wn_body = WN_func_body(wn_pu) ) != NULL &&
00280 WN_operator(wn_body) == OPR_BLOCK &&
00281 ( ( wn_last = WN_last(wn_body) ) == NULL ||
00282 ( WN_operator(wn_last) != OPR_RETURN &&
00283 WN_operator(wn_last) != OPR_RETURN_VAL
00284 #ifdef KEY
00285 && WN_operator(wn_last) != OPR_GOTO_OUTER_BLOCK
00286 #endif
00287 ) ) ) {
00288 wn_return = WN_CreateReturn();
00289 WN_INSERT_BlockLast( wn_body, wn_return );
00290 if ( wn_last ) {
00291 WN_Set_Linenum( wn_return, WN_Get_Linenum(wn_last) );
00292 }
00293 }
00294
00295 CYG_Traverse( wn_pu );
00296 }