4.2.10. 评估算术操作的代价
4.2.10.1. 创建伪函数上下文
回到backend_init,下来是init_dummy_function_start。它初始化了rtl的展开机制,因而我们可以进行一些简单序列的生成。
6518 void
6519 init_dummy_function_start (void) in function.c
6520 {
6521 prepare_function_start (NULL);
6522 }
在这里调用了prepare_function_start来创建伪函数上下文cfun,因为下面的初始化函数需要产生rtl(在正式的代码编译中,只有完成代码解析及前端的优化后,才会生成rtl的表示形式,并交予后端)。
6482 static void
6483 prepare_function_start (tree fndecl) in function.c
6484 {
6485 if (fndecl && DECL_SAVED_INSNS (fndecl))
6486 cfun = DECL_SAVED_INSNS (fndecl);
6487 else
6488 allocate_struct_function (fndecl);
6489 init_emit ();
6490 init_varasm_status (cfun);
6491 init_expr ();
6492
6493 cse_not_expected = ! optimize;
6494
6495
6496 caller_save_needed = 0;
6497
6498
6499 reg_renumber = 0;
6500
6501
6503 rtx_equal_function_value_matters = 1;
6504
6505
6506 virtuals_instantiated = 0;
6507
6508
6509 generating_concat_p = 1;
6510
6511
6512 frame_pointer_needed = 0;
6513 }
结构体function保存了,描述当前被编译函数状态的所有重要的,全局及静态变量。
176 struct function GTY(()) in function.h
177 {
178 struct eh_status *eh;
179 struct stmt_status *stmt;
180 struct expr_status *expr;
181 struct emit_status *emit;
182 struct varasm_status *varasm;
183
184
185
186
187 tree decl;
188
189
190 struct function *outer;
191
192
195 int pops_args;
196
197
200 int args_size;
201
202
205 int pretend_args_size;
206
207
209 int outgoing_args_size;
210
211
213 rtx arg_offset_rtx;
214
215
217 CUMULATIVE_ARGS args_info;
218
219
223 rtx return_rtx;
224
225
226 rtx internal_arg_pointer;
227
228
230 const char *cannot_inline;
231
232
234 struct initial_value_struct *hard_reg_initial_vals;
235
236
237 int x_function_call_count;
238
239
242 tree x_nonlocal_labels;
243
244
248 rtx x_nonlocal_goto_handler_slots;
249
250
252 rtx x_nonlocal_goto_handler_labels;
253
254
257 rtx x_nonlocal_goto_stack_level;
258
259
263 rtx x_cleanup_label;
264
265
268 rtx x_return_label;
269
270
273 rtx x_naked_return_label;
274
275
276 rtx computed_goto_common_label;
277 rtx computed_goto_common_reg;
278
279
281 rtx x_save_expr_regs;
282
283
285 rtx x_stack_slot_list;
286
287
288 tree x_rtl_expr_chain;
289
290
292 rtx x_tail_recursion_label;
293
294
295 rtx x_tail_recursion_reentry;
296
297
301 rtx x_arg_pointer_save_area;
302
303
306 rtx x_clobber_return_insn;
307
308
311 HOST_WIDE_INT x_frame_offset;
312
313
316 tree x_context_display;
317
318
325 tree x_trampoline_list;
326
327
328 rtx x_parm_birth_insn;
329
330
332 rtx x_last_parm_insn;
333
334
336 unsigned int x_max_parm_reg;
337
338
342 rtx * GTY ((length ("%h.x_max_parm_reg"))) x_parm_reg_stack_loc;
343
344
345 struct temp_slot *x_temp_slots;
346
347
348 int x_temp_slot_level;
349
350
351 int x_var_temp_slot_level;
352
353
357 int x_target_temp_slot_level;
358
359
361 struct var_refs_queue *fixup_var_refs_queue;
362
363
364 int inlinable;
365 int no_debugging_symbols;
366 rtvec original_arg_vector;
367 tree original_decl_initial;
368
370 rtx inl_last_parm_insn;
371
372 int inl_max_label_num;
373
374
375 int funcdef_no;
376
377
378
379
380 struct machine_function * GTY ((maybe_undef (""))) machine;
381
382 int stack_alignment_needed;
383
384 int preferred_stack_boundary;
385
386 bool recursive_call_emit;
387
388
389 struct language_function * language;
390
391
392
393
395 rtx epilogue_delay_list;
396
397
399 enum function_frequency {
400
402 FUNCTION_FREQUENCY_UNLIKELY_EXECUTED,
403
404 FUNCTION_FREQUENCY_NORMAL,
405
407 FUNCTION_FREQUENCY_HOT
408 } function_frequency;
409
410
412 int max_jumptable_ents;
413
414
415
416
418 unsigned int returns_struct : 1;
419
420
422 unsigned int returns_pcc_struct : 1;
423
424
425 unsigned int returns_pointer : 1;
426
427
428 unsigned int needs_context : 1;
429
430
431 unsigned int calls_setjmp : 1;
432
433
434 unsigned int calls_longjmp : 1;
435
436
438 unsigned int calls_alloca : 1;
439
440
441 unsigned int calls_eh_return : 1;
442
443
444 unsigned int calls_constant_p : 1;
445
446
448 unsigned int has_nonlocal_label : 1;
449
450
452 unsigned int has_nonlocal_goto : 1;
453
454
455 unsigned int contains_functions : 1;
456
457
458 unsigned int has_computed_jump : 1;
459
460
464 unsigned int is_thunk : 1;
465
466
471 unsigned int all_throwers_are_sibcalls : 1;
472
473
475 unsigned int instrument_entry_exit : 1;
476
477
478 unsigned int profile : 1;
479
480
482 unsigned int limit_stack : 1;
483
484
485 unsigned int stdarg : 1;
486
487
491 unsigned int x_whole_function_mode_p : 1;
492
493
500 unsigned int x_dont_save_pending_sizes_p : 1;
501
502
503 unsigned int uses_const_pool : 1;
504
505
506 unsigned int uses_pic_offset_table : 1;
507
508
509 unsigned int uses_eh_lsda : 1;
510
511
512 unsigned int arg_pointer_save_area_init : 1;
513
514
516 unsigned int rtl_inline_init : 1;
517
518
519 unsigned int saved_for_inline : 1;
520 };
其结构中前6个成员是非常重要的部分。其中,eh_status控制了函数的异常处理;stmt_status记录了语句对栈,数据流的累积效应,这些效应将影响当前语句的翻译;expr_status则记录了函数被调用及退出的行为;emit_status控制相应的rtx形式指令的生成;varasm_status提供了记录函数中常量的方法。
6434 void
6435 allocate_struct_function (tree fndecl) in function.c
6436 {
6437 tree result;
6438
6439 cfun = ggc_alloc_cleared (sizeof (struct function));
6440
6441 max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
6442
6443 cfun->stack_alignment_needed = STACK_BOUNDARY;
6444 cfun->preferred_stack_boundary = STACK_BOUNDARY;
6445
6446 current_function_funcdef_no = funcdef_no++;
6447
6448 cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL;
6449
6450 init_stmt_for_function ();
6451 init_eh_for_function ();
6452
6453 (*lang_hooks.function.init) (cfun);
6454 if (init_machine_status)
6455 cfun->machine = (*init_machine_status) ();
6456
6457 if (fndecl == NULL)
6458 return;
…
6477 }
在上面,current_function_funcdef_no,current_function_returns_pcc_struct,current_function_returns_struct,current_function_returns_pointer,max_parm_reg,current_function_needs_context都是用于从function结构体中选择特定成员的宏。例如。
558 #define current_function_funcdef_no (cfun->funcdef_no) in function.h
567 #define max_parm_reg (cfun->x_max_parm_reg)
在6441行,对于x86机器,LAST_VIRTUAL_REGISTER被定义成FIRST_PSEUDO_REGISTER +4。其值是57,它定义了可被用于rtx形式代码的最大寄存器数目。
在6443及6444行,STACK_BOUNDARY定义了对栈的对齐边界要求。对于x86,这是32(4字节)。
在6446行,funcdef_no为用于概要分析(profiling)及调试等目的的标签赋予唯一的号码。在function 结构体相应的域则记录这个值。
接下来,在6450及6451行,函数init_stmt_for_function,init_eh_for_function仅是分配了结构体中的eh及stmt域,它们分别用于异常处理及语句。
在6453行,钩子lang_hooks.function.init对于C++语言是cxx_push_function_context。在当前上下文环境中,它仅为function对象分配language_function实例。结构体language_function将保存及恢复那些记录当前函数编译进度的变量。它被用于嵌套函数。
在6454行,对于x86机器,init_machine_status指向ix86_init_machine_status。它为function 对象创建了machine_function的实例,这个结构保存了与函数处理相关的机器信息。
在6457行,在这次的调用中,fndecl为null,函数在此返回。