GCC-3.4.6源代码学习笔记(167)
来源:互联网 发布:网络棋牌骗局 编辑:程序博客网 时间:2024/06/07 05:31
5.13.5.2. 为待定变量发布汇编
回到finish_file,我们已经看到flag_unit_at_a_time在‘-O2’以上优化级别中设置为1。这个标记也可以由选项-funit-at-a-time来设定,【6】对其描述如下:
在开始产生代码之前,解析整个编译单元。这允许进行某些额外的优化,不过会消耗更多内存(总体而言)。使用unit-at-a-time模式有一些兼容性问题:
使能unit-at-a-time模式可能改变函数,变量及最顶层汇编语句的发布次序,并将很可能破坏依赖于特定次序的代码。然而大多数这样的最顶层汇编语句可以为段属性所替代。选项‘fno-toplevel-reorder’可以被用来保持输入文件中的次序,以某些优化作为代价。
unit-at-a-time模式移除未被引用的静态变量及函数。当一个汇编语句直接指向除此之外不被使用的变量或函数时,这可能导致未定义的引用。在这个情形下,要么把该变量、函数列为这个汇编语句的一个操作数,或者在顶层汇编语句的情形下,属性used应该用在声明中。
静态函数现在可以使用破坏直接调用函数的汇编语句的非标准传入约定。再一次,属性used将防止这个行为。
作为一个临时的变通,可以使用‘-fno-unit-at-a-time’,不过这个方案可能不会被今后的GCC支持。
finish_file (continue)
2850 if (flag_unit_at_a_time)
2851 {
2852 cgraph_finalize_compilation_unit();
2853 cgraph_optimize();
2854 }
为执行优化,我们需要知道代码间的关系,然后我们可以根据探测出的关系剥除重复的部分。因此在这里,下面的函数分析编译单元并构建一个图来描述其中的依赖关系,数据流及控制流。
368 void
369 cgraph_finalize_compilation_unit (void) in cgraphunit.c
370 {
371 struct cgraph_node *node;
372
373 if (!flag_unit_at_a_time)
374 {
375 cgraph_assemble_pending_functions ();
376 return;
377 }
378
379 cgraph_varpool_assemble_pending_decls();
380 if (!quiet_flag)
381 fprintf (stderr,"/nAnalyzing compilation unit/n");
记得如果声明在这个编译单元以外可见,它被记录入队列cgraph_varpool_nodes_queue。在这里如果这个队列不是空的,所保存的声明应该已经有汇编产生;否则就应该在这里产生。
612 bool
613 cgraph_varpool_assemble_pending_decls (void) in cgraph.c
614 {
615 bool changed = false;
616
617 while (cgraph_varpool_nodes_queue)
618 {
619 tree decl = cgraph_varpool_nodes_queue->decl;
620 struct cgraph_varpool_node *node = cgraph_varpool_nodes_queue;
621
622 cgraph_varpool_nodes_queue= cgraph_varpool_nodes_queue->next_needed;
623 if (!TREE_ASM_WRITTEN (decl))
624 {
625 assemble_variable (decl, 0, 1, 0);
626 changed = true;
627 }
628 node->next_needed = NULL;
629 }
630 return changed;
631 }
上面的623行,在一个VAR_DECL中,TREE_ASM_WRITTEN如果不是0,表示已经写入汇编代码;否则就要调用assemble_variable。注意自动变量不使用这个函数发布汇编。
5.13.5.2.1. 内存分配
在这次调用中,参数don’t_output_data是0,表示确实输出初始值。那么在下面1344行,在当前这个版本中,对于所有的前端,钩子prepare_assemble_variable都是NULL。
1335 void
1336 assemble_variable (tree decl, inttop_level ATTRIBUTE_UNUSED, in varasm.c
1337 int at_end ATTRIBUTE_UNUSED,int dont_output_data)
1338 {
1339 const char*name;
1340 unsigned int align;
1341 int reloc = 0;
1342 rtx decl_rtl;
1343
1344 if (lang_hooks.decls.prepare_assemble_variable)
1345 (*lang_hooks.decls.prepare_assemble_variable)(decl);
1346
1347 last_assemble_variable_decl = 0;
1348
1349 /* Normally no needto say anything here for external references,
1350 since assemble_external is called by thelanguage-specific code
1351 when a declaration is first seen. */
1352
1353 if (DECL_EXTERNAL (decl))
1354 return;
1355
1356 /* Output noassembler code for a function declaration.
1357 Only definitions of functions outputanything. */
1358
1359 if (TREE_CODE (decl) == FUNCTION_DECL)
1360 return;
1361
1362 /* Do nothing forglobal register variables. */
1363 if (DECL_RTL_SET_P (decl) && GET_CODE(DECL_RTL (decl)) == REG)
1364 {
1365 TREE_ASM_WRITTEN (decl) = 1;
1366 return;
1367 }
1368
1369 /* If type wasincomplete when the variable was declared,
1370 see if it is complete now. */
1371
1372 if (DECL_SIZE (decl) == 0)
1373 layout_decl (decl, 0);
1374
1375 /* Still incomplete=> don't allocate it; treat the tentative defn
1376 (which is what it must have been) as an`extern' reference. */
1377
1378 if (!dont_output_data && DECL_SIZE(decl) == 0)
1379 {
1380 error ("%Jstorage size of `%D' isn'tknown", decl, decl);
1381 TREE_ASM_WRITTEN (decl) = 1;
1382 return;
1383 }
1384
1385 /* The firstdeclaration of a variable that comes through this function
1386 decides whether it is global (in C, hasexternal linkage)
1387 or local (in C, has internal linkage). Sodo nothing more
1388 if this function has already run. */
1389
1390 if (TREE_ASM_WRITTEN (decl))
1391 return;
1392
1393 /* Make suretargetm.encode_section_info is invoked before we set
1394 ASM_WRITTEN. */
1395 decl_rtl = DECL_RTL (decl);
1396
1397 TREE_ASM_WRITTEN (decl) = 1;
1398
1399 /* Do no output if -fsyntax-only. */
1400 if (flag_syntax_only)
1401 return;
能从其初始值构建关联的RTL节点的节点必须是已完成的。在前端中,查看中间树节点是否已完成,是检查其尺寸。因为每个由make_node创建的节点总是具有尺寸0;而仅在layout_decl中,才会计算并设置这个大小尺寸。
然后在1395行,宏DECL_RTL为这个VAR_DECL产生了下面的rtx节点,而变量decl_rtl则指向下面的rtx的MEM节点(对于这个例子,VAR_DECL必须不能被声明为register)。
5.13.5.2.1. 内存配置
那么在下面的代码片段中,开始配置为这个VAR_DECL在MEM节点中分配的内存。
assemble_variable(continue)
1403 app_disable ();
1404
1405 if (! dont_output_data
1406 && ! host_integerp (DECL_SIZE_UNIT(decl), 1))
1407 {
1408 error ("%Jsize of variable '%D' is toolarge", decl, decl);
1409 return;
1410 }
1411
1412 name = XSTR (XEXP (decl_rtl, 0), 0);
1413 if (TREE_PUBLIC (decl) && DECL_NAME(decl))
1414 notice_global_symbol (decl);
1415
1416 /* Compute the alignment of this data. */
1417
1418 align = DECL_ALIGN (decl);
1419
1420 /* In the case forinitialing an array whose length isn't specified,
1421 where we have not yet been able to do thelayout,
1422 figure out the proper alignment now. */
1423 if (dont_output_data && DECL_SIZE(decl) == 0
1424 && TREE_CODE (TREE_TYPE (decl))== ARRAY_TYPE)
1425 align = MAX (align, TYPE_ALIGN (TREE_TYPE(TREE_TYPE (decl))));
1426
1427 /* Some object fileformats have a maximum alignment which they support.
1428 In particular, a.out format supports a maximum alignment of4. */
1429 #ifndef MAX_OFILE_ALIGNMENT
1430 #define MAX_OFILE_ALIGNMENT BIGGEST_ALIGNMENT
1431 #endif
1432 if (align > MAX_OFILE_ALIGNMENT)
1433 {
1434 warning ("%Jalignment of '%D' isgreater than maximum object "
1435 "file alignment. Using%d", decl, decl,
1436 MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
1437 align = MAX_OFILE_ALIGNMENT;
1438 }
1439
1440 /* On some machines,it is good to increase alignment sometimes. */
1441 if (! DECL_USER_ALIGN (decl))
1442 {
1443 #ifdef DATA_ALIGNMENT
1444 align = DATA_ALIGNMENT (TREE_TYPE (decl),align);
1445 #endif
1446 #ifdefCONSTANT_ALIGNMENT
1447 if (DECL_INITIAL (decl) != 0 &&DECL_INITIAL (decl) != error_mark_node)
1448 align = CONSTANT_ALIGNMENT (DECL_INITIAL(decl), align);
1449 #endif
1450 }
1451
1452 /* Reset thealignment in case we have made it tighter, so we can benefit
1453 from it in get_pointer_alignment. */
1454 DECL_ALIGN (decl) = align;
1455 set_mem_align(decl_rtl, align);
1456
1457 if (TREE_PUBLIC (decl))
1458 maybe_assemble_visibility (decl);
首先,作为GNU汇编器的语法,如果一个输入文件的第一行是#NO_APP,或者如果使用了选项‘-f’,空格及注释不会从输入文件中移走。在一个输入文件中,你可以要求在特定的部分移走空格及注释,通过在这个可能包含空格及注释的文本前加入一行#APP,并在该文本后加上一行#NO_APP。这个特性主要目的在于支持编译器中的汇编语句,编译器的输出是没有空格及注释的。在C++中,这主要用于嵌入汇编器,并在函数作用域外的嵌入汇编器块的开头,GCC将自动插入#APP。因此在1403行,如果使用了#APP,在发布汇编之前,首先通过app_disable使用#NO_APP关闭这个#APP。
284 void
285 app_disable (void) in final.c
286 {
287 if (app_on)
288 {
289 fputs (ASM_APP_OFF, asm_out_file);
290 app_on= 0;
291 }
292 }
全局变量app_on如果非0,表示#APP在使用;而ASM_APP_OFF,对于绝大多数目标平台被定义为“#NO_APP”(在剩下的少数中,它被定义为空串)。
接着在1414行,notice_global_symbol收集在这个编译单元中出现的第一个全局变量的名字,它将被用于为匿名名字空间产生内部名字。上面代码的最后部分则是确定该内存的对齐量,即便对于Linux/x86目标平台,在1429行,MAX_OFILE_ALIGNMENT仍未定义,而被设置为下面的BIGGEST_ALIGNMENT(定义为32)。
我们已经看到的,除非显式地使用属性在声明中指出特别的对齐量,节点中的总是false。而在通常的情形中,目标平台会定义DATA_ALIGNMENT来增加中等大小数据的对齐量,以使它适配更少的缓存线(cache line)。另外CONSTANT_ALIGNMENT也被目标平台定义来增加字符串常量的对齐量到字边界,使得调用‘strcpy’拷贝常量可以内联地执行。然后这个精心确定的对齐量将被设置入rtx的MEM节点中,它将在后面指引汇编的发布。
1822 void
1823 set_mem_align (rtx mem, unsigned intalign) in emit-rtl.c
1824 {
1825 MEM_ATTRS (mem) = get_mem_attrs(MEM_ALIAS_SET (mem), MEM_EXPR (mem),
1826 MEM_OFFSET (mem), MEM_SIZE (mem), align,
1827 GET_MODE (mem));
1828 }
宏MEM_ATTRS从rtx提取rtmem域的内容,这个域具有以下定义。
99 typedef struct mem_attrs GTY(()) in rtl.h
100 {
101 HOST_WIDE_INT alias; /* Memory alias set. */
102 tree expr; /* expr corresponding to MEM. */
103 rtx offset; /* Offset from start of DECL, as CONST_INT. */
104 rtx size; /* Size in bytes, as a CONST_INT. */
105 unsigned int align; /* Alignment of MEM in bits. */
106 } mem_attrs;
上面MEM_ALIAS_SET,MEM_EXPR,MEM_OFFSET及MEM_SIZE提取结构体中相应的域(但如果rtmem域是空的返回0,并看到在make_decl_rtl的gen_rtx_MEM中,一个空指针被置入rtmem域)。因此set_mem_align的净效果是在get_mem_attrs的协助下更新保存对齐量的域。
291 static mem_attrs *
292 get_mem_attrs (HOST_WIDE_INT alias, tree expr, rtx offset, rtx size, in emit-rtl.c
293 unsigned int align, enum machine_mode mode)
294 {
295 mem_attrs attrs;
296 void **slot;
297
298 /* If everything is the default, we can justreturn zero.
299 This must match what the correspondingMEM_* macros return when the
300 field is not present. */
301 if (alias == 0 && expr == 0 && offset == 0
302 && (size == 0
303 || (mode != BLKmode &&GET_MODE_SIZE (mode) == INTVAL (size)))
304 && (STRICT_ALIGNMENT&& mode != BLKmode
305 ? align == GET_MODE_ALIGNMENT (mode) : align == BITS_PER_UNIT))
306 return 0;
307
308 attrs.alias = alias;
309 attrs.expr = expr;
310 attrs.offset = offset;
311 attrs.size = size;
312 attrs.align = align;
313
314 slot = htab_find_slot (mem_attrs_htab, &attrs, INSERT);
315 if (*slot == 0)
316 {
317 *slot = ggc_alloc (sizeof (mem_attrs));
318 memcpy (*slot, &attrs, sizeof (mem_attrs));
319 }
320
321 return *slot;
322 }
mem_attrs的所有实例都被缓存在哈希表mem_attrs_htab中以加速查找;并且每个内存属性设置是单件。看到通常地,相同类型的每个声明将具有相同的内存属性设置。
回到assemble_variable,在1458行,maybe_assemble_visibility只是处理具有属性“visibility”的声明。该函数将调用后端的钩子来输出具有所描述可见性(visibility)的名字。我们在这里跳过其处理,【6】对这个属性给出了详细的描述。
- GCC-3.4.6源代码学习笔记(167)
- GCC-3.4.6源代码学习笔记 (100)
- GCC-3.4.6源代码学习笔记 (101)
- GCC-3.4.6源代码学习笔记 (102)
- GCC-3.4.6源代码学习笔记 (103)
- GCC-3.4.6源代码学习笔记 (104)
- GCC-3.4.6源代码学习笔记 (105)
- GCC-3.4.6源代码学习笔记 (106)
- GCC-3.4.6源代码学习笔记(166)
- GCC-3.4.6源代码学习笔记
- GCC-3.4.6源代码学习笔记(6)
- GCC-3.4.6源代码学习笔记(1)
- GCC-3.4.6源代码学习笔记(2)
- GCC-3.4.6源代码学习笔记(3)
- GCC-3.4.6源代码学习笔记(4)
- GCC-3.4.6源代码学习笔记(5)
- GCC-3.4.6源代码学习笔记(7)
- GCC-3.4.6源代码学习笔记(8)
- 如何用Skype远程控制自制智能家居
- 通过js以超链接的形式访问jsp或访问servlet
- 4个常用的的flash图表/饼图/折线图/ppt flash图表
- 汉字编码对照表(gb2312/unicode/utf8)
- IBM服务器分类
- GCC-3.4.6源代码学习笔记(167)
- The project is not a myEclipse hibernate project
- 关于DispatchAction的介绍
- Studying note of GCC-3.4.6 source (167)
- 数据库Oracle10g删除一个表后出现BIN$开头表怎么彻底删除掉?
- leach协议的nam过程实现!(转)
- TCP Socket编程的几点肮脏的问题
- 经典的用户权限管理,数据结构分析设计
- Delphi自定义释放资源过程