Chinaunix首页 | 论坛 | 博客
  • 博客访问: 18443
  • 博文数量: 3
  • 博客积分: 166
  • 博客等级: 入伍新兵
  • 技术积分: 60
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-27 14:01
文章分类
文章存档

2012年(3)

我的朋友

分类: C/C++

2012-03-30 14:51:02

首先来看看plugin都能加载到什么地方,From plugin.def:


 

点击(此处)折叠或打开

  1. /* To hook into pass manager. */
  2. DEFEVENT (PLUGIN_PASS_MANAGER_SETUP)

  3. /* After finishing parsing a type. */
  4. DEFEVENT (PLUGIN_FINISH_TYPE)

  5. /* Useful for summary processing. */
  6. DEFEVENT (PLUGIN_FINISH_UNIT)

  7. /* Allows to see low level AST in C and C++ frontends. */
  8. DEFEVENT (PLUGIN_PRE_GENERICIZE)

  9. /* Called before GCC exits. */
  10. DEFEVENT (PLUGIN_FINISH)

  11. /* Information about the plugin. */
  12. DEFEVENT (PLUGIN_INFO)

  13. /* Called at start of GCC Garbage Collection. */
  14. DEFEVENT (PLUGIN_GGC_START)

  15. /* Extend the GGC marking. */
  16. DEFEVENT (PLUGIN_GGC_MARKING)

  17. /* Called at end of GGC. */
  18. DEFEVENT (PLUGIN_GGC_END)

  19. /* Register an extra GGC root table. */
  20. DEFEVENT (PLUGIN_REGISTER_GGC_ROOTS)

  21. /* Register an extra GGC cache table. */
  22. DEFEVENT (PLUGIN_REGISTER_GGC_CACHES)

  23. /* Called during attribute registration. */
  24. DEFEVENT (PLUGIN_ATTRIBUTES)

  25. /* Called before processing a translation unit. */
  26. DEFEVENT (PLUGIN_START_UNIT)

  27. /* Called during pragma registration. */
  28. DEFEVENT (PLUGIN_PRAGMAS)

  29. /* Called before first pass from all_passes. */
  30. DEFEVENT (PLUGIN_ALL_PASSES_START)

  31. /* Called after last pass from all_passes. */
  32. DEFEVENT (PLUGIN_ALL_PASSES_END)

  33. /* Called before first ipa pass. */
  34. DEFEVENT (PLUGIN_ALL_IPA_PASSES_START)

  35. /* Called after last ipa pass. */
  36. DEFEVENT (PLUGIN_ALL_IPA_PASSES_END)

  37. /* Allows to override pass gate decision for current_pass. */
  38. DEFEVENT (PLUGIN_OVERRIDE_GATE)

  39. /* Called before executing a pass. */
  40. DEFEVENT (PLUGIN_PASS_EXECUTION)

  41. /* Called before executing subpasses of a GIMPLE_PASS in
  42.    execute_ipa_pass_list. */
  43. DEFEVENT (PLUGIN_EARLY_GIMPLE_PASSES_START)

  44. /* Called after executing subpasses of a GIMPLE_PASS in
  45.    execute_ipa_pass_list. */
  46. DEFEVENT (PLUGIN_EARLY_GIMPLE_PASSES_END)

  47. /* Called when a pass is first instantiated. */
  48. DEFEVENT (PLUGIN_NEW_PASS)


猛然一看,似乎应该是PLUGIN_PRE_GENERICIZE - Allows to see low level AST in C and C++ frontends。

但对于GCC一窍不通的人来说,真的很难确定。

不如写个测试plugin把各个不明确的Event位置都打印一下,应该一看就明白了

动手吧。

各个回调函数:


 

点击(此处)折叠或打开

  1. void pass_gate_callback(void *gcc_data, void *user_data)
  2. {
  3.     //std::cout << "Gate :" << current_pass->name << std::endl;
  4.     std::cout << "************pass gate"<< std::endl;
  5. }

  6. void finish_type(void *gcc_data, void *user_data)
  7. {
  8.     std::cout << "finish Type"<< std::endl;
  9. }

  10. void finish_unit(void *gcc_data, void *user_data)
  11. {
  12.     std::cout << "finish UNIT"<< std::endl;
  13. }

  14. void pre_genericize(void *gcc_data, void *user_data)
  15. {
  16.     std::cout << "pre_genericize"<< std::endl;
  17. }

  18. void start_unit(void *gcc_data, void *user_data)
  19. {
  20.     std::cout << "start unit"<< std::endl;
  21. }


注册回调函数


 

点击(此处)折叠或打开

  1. register_callback(plugin_info->base_name,
  2.        PLUGIN_OVERRIDE_GATE,
  3.        &pass_gate_callback,
  4.        0);
  5.                       
  6.         
  7.     register_callback(plugin_info->base_name,
  8.         PLUGIN_FINISH_TYPE,
  9.         &finish_type,
  10.         0);
  11.         
  12.     register_callback(plugin_info->base_name,
  13.         PLUGIN_FINISH_UNIT,
  14.         &finish_unit,
  15.         0);
  16.         
  17.     register_callback(plugin_info->base_name,
  18.         PLUGIN_PRE_GENERICIZE,
  19.         &pre_genericize,
  20.         0);
  21.         
  22.         
  23.     register_callback(plugin_info->base_name,
  24.         PLUGIN_START_UNIT,
  25.         &start_unit,
  26.         0);


 

编译成plugintest.so,测试 g -fplugin=./helloworld.so test.cxx 为了简化输出的内容, test.cxx很简单,并且不包括任何头文件

点击(此处)折叠或打开

  1. class hello
  2. {
  3. };

  4. double f = 1.00;

  5. int foo()
  6. {
  7.   return 0;
  8. }

  9. int main()
  10. {
  11.    foo();

  12.    return 0;
  13. }


用GCC load它,输出到文件

“g++ -fplugin=./plugintest.so test.cxx > passes.txt ”。

结果是 

 

start unit ----->finish type------>pre genericize----->pre genericize------>很多pass gate-----> finish unit  

 

怎么样?明白了吗?还是一头雾水。 

 

parsing a type 

 

当然PLUGIN_FINISH_TYPE很明确 - After finishing parsing a type。

那么为什么只有一个finish type呢? 

合理的解释应该是,语言内置type是不需要parsing的,编译器只需要parse用户自定义type,例如class hello。 

我们可以在test.cxx中再定义一个struct来验证一下 

 

start unit -----> 2个finish type ------> 2个pre genericize ------> 很多pass gate ----->

finish unit 

 

猜测是正确的。 

 

GENERICIZE 

 

现在在来看Genericize,google一下,看下GCC的internal document第九章,

一般的GCC的编译过程可以概括如下 

 

Parsing file ----生成AST/Generic--------> Gimplifier --------> Tree SSA(树优化) -------> RTL

--------> ASM

 

这么看来,如果我们大胆猜测一下,PLUGIN_PRE_GENERICIZE是不是就是生成Generic之前的位置?

为什么加了一个struct还是只有两次Genericize? 

猜测是,Genericize是用来生成Generic语法树的,那么,只有函数逻辑才需要生成语法树吧.

两次Genericize是针对foo和main吧。 

做一下验证,

去掉foo,还真只有一个genericize了。 

 

start unit -----> finish type ------> pre genericize ------> 很多pass gate ----->

finish unit 

 

为class hello增加一个成员函数(foo已经去掉了),结果是 

 

start unit -----> pre genericize ----> finish type ------> pre genericize ------>很多pass gate -----> finish unit 

 

哦,猜测应该是正确的。

 

 Pass Gate

 

PLUGIN_OVERRIDE_GATE的定义是“override pass gate decision for current_pass”,

而在internal文档中23.8节 

“After the original gate function for a pass is called, its result - the gate status - is stored as an integer. Then the event PLUGIN_OVERRIDE_GATE is invoked, with a pointer to the gate status in the gcc_data parameter to the callback function. A nonzero value of the gate status means that the pass is to be executed. You can both read and write the gate status via the passed pointer.” 

其在struct opt_pass中的定义为  

 

点击(此处)折叠或打开

  1. /* If non-null, this pass and all sub-passes are executed only if
  2.      the function returns true. */
  3.   bool (*gate) (void);

简单说,当一个pass将要执行的时候,GCC使用gate函数来判断是否要执行这个pass和它的子pass。 

所以说PLUGIN_OVERRIDE_GATE是恰恰好在一个pass开始之前的位置。 

 

 Pass

 

Pass这个概念真让我迷惑了很久。

从网上一篇文章中说“分析程序对应的英文是pass,即多趟扫描编译器中某一趟扫描所使用的扫描程序。”

那么扫描源码生成AST的过程算不算pass? GCC internal document第九章开头又说 

 

  • : The language front end turns text into bits.
  • : The bits are turned into something we can optimize.
  • : Sequencing the optimization passes.
  • : Optimizations on a high-level representation.
  • : Optimizations on a low-level representation.

” 

 

那么看来parsing算是pass了,那么PLUGIN_OVERRIDE_GATE会不会加在parsing源码之前呢?

当然不会,从前面的测试我们知道PLUGIN_OVERRIDE_GATE只加载在optimization pass之前。

也很合理,无论如何源码parsing是不能省略的,所以它不用gate来判断,而optimization pass则需要,

想想-O2,-O3吧。

 

 结论 

 

分析了这么半天,我们应该知道什么时候是 “正好AST之后,优化之前了” -

在第一个PLUGIN_OVERRIDE_GATE的时候。

 

解决方案其实一直都有,从

~boris/blog/2010/05/03/parsing-cxx-with-gcc-plugin-part-1/

 

“We don’t want to perform any other passes since that would only be a waste of time.

All we need is the C++ AST. At first it may seem that PLUGIN_FINISH_UNIT is a good place

 to run our code. However, a number of passes are performed before it (you can test this by

 registering a callback for the PLUGIN_OVERRIDE_GATE event which will allow you to see all

the passes that are being executed).

One way to achieve what we want would be to register a callback for the PLUGIN_OVERRIDE_GATE event.

This callback is called before every pass and it allows the plugin to decide whether to run

the pass in question. The first call to this callback will then by definition be before any

other pass has run. We can then call our code from this first execution of the callback and

then terminate GCC.” 

 

结论很清楚

但如果你一开始就迷惑于pass是否只包含optimize pass,还是连带source file parsing一起包含了,

那么你对他的结论就有点不确信了。

所幸,分析了半天,他说的还真对(废话)。

阅读(1950) | 评论(0) | 转发(0) |
0

上一篇:GCC Plugins简介

下一篇:GCC GENERIC tree

给主人留下些什么吧!~~