GCC passes分析(一)

来源:互联网 发布:同花顺龙虎榜数据 编辑:程序博客网 时间:2024/06/05 02:04

遍(passes)是GCC编译器源代码中的一个重要概念,对它们的理解是了解GCC源代码的架构的基础。本系列文章打算以此为契机,对GCC编译器源代码做一个概要性的分析,分析对象为GCC 4.9.1版本。

源代码中,与Pass相关的文件有:

  1. passes.c

  2. passes.def

  3. pass_manager.h

另外,安装编译器的过程中,还会生成一个与pass相关的中间文件pass-instances.def,是源码下面的脚本文件gen-pass-instances.awk读取passes.def文件而生成的。

1)文件passes.def

  本文件使用了4个宏:

INSERT_PASSES_AFTER;PUSH_INSERT_PASSES_WITHIN;NEXT_PASSTERMINATE_PASS_LIST
2)文件passes-instances.def

  本文件是由文件passes.def生成,内容与passes.def相似,只是增加了对每个pass出现(成为实例,instance)的统计。例如

NEXT_PASS (pass_forwprop)

passes.def中出现了4次,则该宏在pass-instance.def中的出现形式为

NEXT_PASS (pass_forwprop, 1)NEXT_PASS (pass_forwprop, 2)NEXT_PASS (pass_forwprop, 3)NEXT_PASS (pass_forwprop, 4)
3)各种宏的使用(pass_manger.h, passes.c)

    在pass_manager.h文件中,使用方式如下。

#define INSERT_PASSES_AFTER(PASS)#define PUSH_INSERT_PASSES_WITHIN(PASS)#define POP_INSERT_PASSES()#define NEXT_PASS(PASS, NUM) opt_pass *PASS ## _ ## NUM#define TERMINATE_PASS_LIST()#include "pass-instances.def"

实际此文件只在pass_manager类的定义中,使用了一个宏”NEXT_PASS”,并把类的名称与实例编号连接起来。例如对于宏pass_forwprop,生成形如:

opt_pass *pass_forwprop_1;......opt_pass *pass_forwprop_4;</span>
的几个定义,也即所有的类实例作为pass_manager类的成员变量。而其他几个宏,都被定义为空。

这些宏在passes.c中的使用略为复杂。首先需要解析其他一些相关的宏,主要包括GCC_PASS_LISTSDEF_PASS_LIST,而它们在不同文件中的定义不一样。在pass_manager.h中,对它们的定义和使用如下所示。

#define GCC_PASS_LISTS \  DEF_PASS_LIST (all_lowering_passes) \  DEF_PASS_LIST (all_small_ipa_passes) \  DEF_PASS_LIST (all_regular_ipa_passes) \  DEF_PASS_LIST (all_passes)#define DEF_PASS_LIST(LIST) PASS_LIST_NO_##LIST,enum pass_list{  GCC_PASS_LISTS  PASS_LIST_NUM};#undef DEF_PASS_LIST

其作用就是定义了一个枚举数据类型pass_list,把宏展开后,可知其包含5个元素,等价于下述代码段。

enum pass_list{  PASS_LIST_NO_all_lowering_passes,  PASS_LIST_NO_all_small_ipa_passes,  PASS_LIST_NO_all_regular_ipa_passes,  PASS_LIST_NO_all_passes,  PASS_LIST_NUM}

而在passes.c中,是pass_manager的构造函数pass_manager::pass_manager使用了GCC_PASS_LISTSDEF_PASS_LIST以及passes.def文件中的4个宏。代码

#define DEF_PASS_LIST(LIST) pass_lists[PASS_LIST_NO_##LIST] = &LIST;  GCC_PASS_LISTS#undef DEF_PASS_LIST

的作用是给几个数组赋初值,实际对应于下述语句序列:

pass[PASS_LIST_NO_all_lowering_passes] = &all_lowering_passes;pass[PASS_LIST_NO_all_small_ipa_passes] = &all_small_ipa_passes;pass[PASS_LIST_NO_all_regular_ipa_passes] = &all_regular_ipa_passes;pass[PASS_LIST_NO_all_passes] = &all_passes;

而用来赋值的4个数值all_lowering_passes,是构造函数的形式参数。

passes.c文件中对于passes.def中所使用到的四个针对宏的操作,也是采用先定义宏,在把def文件include进来的做法。定义宏的语句如下:

#define INSERT_PASSES_AFTER(PASS) \  p = &(PASS);#define PUSH_INSERT_PASSES_WITHIN(PASS) \  { \    opt_pass **p = &(PASS ## _1)->sub;#define POP_INSERT_PASSES() \  }#define NEXT_PASS(PASS, NUM) \  do { \    gcc_assert (NULL == PASS ## _ ## NUM); \    if ((NUM) == 1)                              \      PASS ## _1 = make_##PASS (m_ctxt);          \    else                                         \      {                                          \        gcc_assert (PASS ## _1);                 \        PASS ## _ ## NUM = PASS ## _1->clone (); \      }                                          \    p = next_pass_1 (p, PASS ## _ ## NUM, PASS ## _1);  \  } while (0)#define TERMINATE_PASS_LIST() \  *p = NULL;

include进来的文件是pass-instances.def,以该文件开头的少量定义为例子,则上述定义实际上产生的语句序列为:

p = &(all_lowering_passes);do{  gcc_assert(NULL == pass_warn_unused_result_1);  if(1 == 1)    pass_warn_unused_result_1 = make_pass_warn_unused_result(m_ctxt);  else    {       gcc_assert(pass_warn_unused_result_1);       pass_warn_unused_result_1 = pass_warn_unused_result_1->clone();    }    p = next_pass_1(p, pass_warn_unused_result_1, pass_warn_unused_result_1);}while(0)*p == NULL;

从以上的代码分析来看,NEXT_PASS的功能就是利用opt_passnext域来建立一个链表,链表的头是有名字的opt_pass,也即all_lowering_passesall_small_ipa_passesall_regular_ipa_passesall_passes之一。

INSERT_PASSES_AFTER(PASS)的使得当前类型为opt_pass **类型的指针p指向PASSPASS在文件pass.def中对应于5pass实例,分别是all_lowering_passesall_small_ipa_passesall_regular_ipa_passesall_late_ipa_passesall_passes。而这5个实例也是文件pass_manager.h中定义的类pass_manager5public类型的成员变量。next_pass_1的代码如下:

static opt_pass **next_pass_1 (opt_pass **list, opt_pass *pass, opt_pass *initial_pass){  /* Every pass should have a name so that plugins can refer to them.  */  gcc_assert (pass->name != NULL);  add_pass_instance (pass, false, initial_pass);  *list = pass;  return &(*list)->next;}

此函数执行前后的效果如下图所示。


也即NEXT_PASS是建立一个opt_pass的链表,表头为all_lowering_passes5个变量之一。

而宏POP_INSERT_PASSES则是和 POP_INSERT_PASSES成对出现,同样是建立链表,但是改成使用opt_passsub域。








0 0
原创粉丝点击