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_data0,表示确实输出初始值。那么在下面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则指向下面的rtxMEM节点(对于这个例子,VAR_DECL必须不能被声明为register)。

t

5.13.5.2.1.       内存配置

那么在下面的代码片段中,开始配置为这个VAR_DECLMEM节点中分配的内存。

 

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’拷贝常量可以内联地执行。然后这个精心确定的对齐量将被设置入rtxMEM节点中,它将在后面指引汇编的发布。

 

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_ATTRSrtx提取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_SETMEM_EXPRMEM_OFFSETMEM_SIZE提取结构体中相应的域(但如果rtmem域是空的返回0,并看到在make_decl_rtlgen_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】对这个属性给出了详细的描述。

原创粉丝点击