GCC - GIMPLE IR学习之pass

  源码经过GCC前端的词法/语法、语义分析之后,生成AST/GENERIC,再转换为前端语言无关的中间表示GIMPLE,之后GCC再对GIMPLE进行GIMPLE低级化、构建cfg等一系列处理,这一系列操作称为GCC Pass(处理过程)。每个pass完成一种处理,其输出结果作为下一个pass的输入。在此以gcc-8.2.0的源码为例说明。
GCC中所有的pass组织在passes.def链表中,源码如下:

 /*
 Macros that should be defined when using this file:
    INSERT_PASSES_AFTER (PASS)
    PUSH_INSERT_PASSES_WITHIN (PASS)
    POP_INSERT_PASSES ()
    NEXT_PASS (PASS)
    TERMINATE_PASS_LIST (PASS)
*/
/* All passes needed to lower the function into shape optimizers can
   operate on.  These passes are always run first on the function, but
   backend might produce already lowered functions that are not processed
   by these passes.  */
INSERT_PASSES_AFTER (all_lowering_passes)
NEXT_PASS (pass_warn_unused_result);
NEXT_PASS (pass_diagnose_omp_blocks);
NEXT_PASS (pass_diagnose_tm_blocks);
NEXT_PASS (pass_lower_omp);
NEXT_PASS (pass_lower_cf);
NEXT_PASS (pass_lower_tm);
NEXT_PASS (pass_refactor_eh);
NEXT_PASS (pass_lower_eh);
NEXT_PASS (pass_build_cfg);
....
POP_INSERT_PASSES ()
NEXT_PASS (pass_clean_state);
TERMINATE_PASS_LIST (all_passes)

GCC描述pass的核心数据结构在passes.c文件中,优化pass分为4大类,分别是:GIMPLE_PASS、RTL_PASS、SIMPLE_IPA_PASS、IPA_PASS。其中GIMPLE_PASS、SIMPLE_IPA_PASS和IPA_PASS都是以GIMPLE中间表示为处理对象,RTL_PASS以RTL为处理对象,源码如下:

enum opt_pass_type
{
  GIMPLE_PASS,
  RTL_PASS,
  SIMPLE_IPA_PASS,
  IPA_PASS
};

pass的主要数据信息如下,其中next字段用于将这些pass组织成链表:

struct pass_data
{
  enum opt_pass_type type;    // pass类型
  const char *name;           //pass名称
  unsigned int optinfo_flags; //在dumpfile.h中定义的-fopt-info优化组标志。
  timevar_id_t tv_id;         //关联该pass的timevar id
  /* 通过此过程输入和输出的属性集.  */
  unsigned int properties_required;  //执行该pass需要满足的属性
  unsigned int properties_provided;  //执行该pass所提供的属性
  unsigned int properties_destroyed; //执行该pass所破坏的属性
  /* TODO标记 */
  unsigned int todo_flags_start;    //执行该pass之前需要执行的标记
  unsigned int todo_flags_finish;   //执行该pass之后需要执行的标记
};

class opt_pass : public pass_data
{
public:
  virtual ~opt_pass () { }
  /* 创建当前pass的一个克隆 */
  virtual opt_pass *clone ();
  virtual void set_pass_param (unsigned int, bool);
  /* 当函数返回true时,才执行此pass和所有子pass。默认实现返回true */
  virtual bool gate (function *fun);
  virtual unsigned int execute (function *fun);

protected:
  opt_pass (const pass_data&, gcc::context *);

public:
  /* 要运行的子pass列表 */
  opt_pass *sub;
  /* pass中的下一个  */
  opt_pass *next;
  /* 静态编号 */
  int static_pass_number;

protected:
  gcc::context *m_ctxt;
}

//  四种pass结构源码如下

/* Description of GIMPLE pass.  */
class gimple_opt_pass : public opt_pass
{
protected:
  gimple_opt_pass (const pass_data& data, gcc::context *ctxt)
    : opt_pass (data, ctxt)
  {
  }
};
/* Description of RTL pass.  */
class rtl_opt_pass : public opt_pass
{
protected:
  rtl_opt_pass (const pass_data& data, gcc::context *ctxt)
    : opt_pass (data, ctxt)
  {
  }
};
/* Description of IPA pass with generate summary, write, execute, read and transform stages.  */
class ipa_opt_pass_d : public opt_pass
{
public:
  void (*generate_summary) (void);

  void (*write_summary) (void);

  void (*read_summary) (void);

  void (*write_optimization_summary) (void);

  void (*read_optimization_summary) (void);

  void (*stmt_fixup) (struct cgraph_node *, gimple **);

  unsigned int function_transform_todo_flags_start;
  unsigned int (*function_transform) (struct cgraph_node *);
  void (*variable_transform) (varpool_node *);

protected:
  ipa_opt_pass_d (const pass_data& data, gcc::context *ctxt,
		  void (*generate_summary) (void),
		  void (*write_summary) (void),
		  void (*read_summary) (void),
		  void (*write_optimization_summary) (void),
		  void (*read_optimization_summary) (void),
		  void (*stmt_fixup) (struct cgraph_node *, gimple **),
		  unsigned int function_transform_todo_flags_start,
		  unsigned int (*function_transform) (struct cgraph_node *),
		  void (*variable_transform) (varpool_node *))
    : opt_pass (data, ctxt),
      generate_summary (generate_summary),
      write_summary (write_summary),
      read_summary (read_summary),
      write_optimization_summary (write_optimization_summary),
      read_optimization_summary (read_optimization_summary),
      stmt_fixup (stmt_fixup),
      function_transform_todo_flags_start (function_transform_todo_flags_start),
      function_transform (function_transform),
      variable_transform (variable_transform)
  {
  }
}
/* Description of simple IPA pass.  Simple IPA passes have just one execute hook.  */
class simple_ipa_opt_pass : public opt_pass
{
protected:
  simple_ipa_opt_pass (const pass_data& data, gcc::context *ctxt)
    : opt_pass (data, ctxt)
  {
  }
};

这些pass中gimple_opt_pass、rtl_opt_pass、simple_ipa_opt_pass,三种pass中只包含一个opt_pass,即它们的存储结构体形式相同,只是其类型和内容不同,只有ipa_opt_pass_d包含了很多额外的函数。

  GCC中的这些pass在不同的contexts中,许多pass被多次调用,例如dead code elimination死代码消除就是在对GIMPLE序列先删除一部分死代码之后,继续根据流程控制执行删除,还有constant propagation常量传播,它也是一个被多次调用的过程间的操作,包括fixup_cfg调整cfg,也是执行完一些pass后被多次调用,以对cfg进行调整。

  pass序列大致可以分为两部分:Passes on Gimple和Passes on RTL,示意如下:
pass

许多pass也被组织到相关的pass group中进行管理,例如pass_build_ssa_passes:

PUSH_INSERT_PASSES_WITHIN (pass_build_ssa_passes)
   NEXT_PASS (pass_fixup_cfg);
   NEXT_PASS (pass_build_ssa);
   NEXT_PASS (pass_warn_nonnull_compare);
   NEXT_PASS (pass_ubsan);
   NEXT_PASS (pass_early_warn_uninitialized);
   NEXT_PASS (pass_nothrow);
   NEXT_PASS (pass_rebuild_cgraph_edges);
POP_INSERT_PASSES ()

  对于GIMPLE_PASS、RTL_PASS类型的pass链表,可调用execute_pass_list方法进行遍历每个pass及其子pass,对于SIMPLE_IPA_PASS和IPA_PASS类型的pass链表,可调用execute_ipa_pass_list方法进行遍历。execute_pass_listexecute_ipa_pass_list方法源码如下:

void
execute_pass_list (function *fn, opt_pass *pass)
{
  gcc_assert (fn == cfun);
  execute_pass_list_1 (pass);
  if (cfun && fn->cfg)
    {
      free_dominance_info (CDI_DOMINATORS);
      free_dominance_info (CDI_POST_DOMINATORS);
    }
}
....
static void
execute_pass_list_1 (opt_pass *pass)
{
  do
    {
      gcc_assert (pass->type == GIMPLE_PASS
		  || pass->type == RTL_PASS);

      if (cfun == NULL)
	return;
      if (execute_one_pass (pass) && pass->sub)
	execute_pass_list_1 (pass->sub);
      pass = pass->next;
    }
  while (pass);
}


/* Same as execute_pass_list but assume that subpasses of IPA passes are local passes.  */
void
execute_ipa_pass_list (opt_pass *pass)
{
  do
    {
      gcc_assert (!current_function_decl);
      gcc_assert (!cfun);
      gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
      if (execute_one_pass (pass) && pass->sub)
	{
	  if (pass->sub->type == GIMPLE_PASS)
	    {
	      invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_START, NULL);
	      do_per_function_toporder ((void (*)(function *, void *))
					  execute_pass_list,
					pass->sub);
	      invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_END, NULL);
	    }
	  else if (pass->sub->type == SIMPLE_IPA_PASS
		   || pass->sub->type == IPA_PASS)
	    execute_ipa_pass_list (pass->sub);
	  else
	    gcc_unreachable ();
	}
      gcc_assert (!current_function_decl);
      symtab->process_new_functions ();
      pass = pass->next;
    }
  while (pass);
}

execute_pass_list方法中调用execute_pass_list_1方法,并再在其中调用execute_one_pass方法进行来对pass进行处理。在execute_ipa_pass_list方法中,主要也是递归调用了execute_one_pass方法来对pass进行处理。


References:

  • 《深入分析GCC》王亚刚.编著
原创文章 38 获赞 13 访问量 4010

猜你喜欢

转载自blog.csdn.net/qq_36287943/article/details/105760610
gcc
今日推荐