2012年(3)
分类: C/C++
2012-03-30 14:51:02
首先来看看plugin都能加载到什么地方,From plugin.def:
点击(此处)折叠或打开
猛然一看,似乎应该是PLUGIN_PRE_GENERICIZE - Allows to see low level AST in C and C++ frontends。
但对于GCC一窍不通的人来说,真的很难确定。
不如写个测试plugin把各个不明确的Event位置都打印一下,应该一看就明白了
动手吧。
各个回调函数:
点击(此处)折叠或打开
注册回调函数
点击(此处)折叠或打开
点击(此处)折叠或打开
用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中的定义为
点击(此处)折叠或打开
简单说,当一个pass将要执行的时候,GCC使用gate函数来判断是否要执行这个pass和它的子pass。
所以说PLUGIN_OVERRIDE_GATE是恰恰好在一个pass开始之前的位置。
Pass
Pass这个概念真让我迷惑了很久。
从网上一篇文章中说“分析程序对应的英文是pass,即多趟扫描编译器中某一趟扫描所使用的扫描程序。”
那么扫描源码生成AST的过程算不算pass? GCC internal document第九章开头又说
“
”
那么看来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一起包含了,
那么你对他的结论就有点不确信了。
所幸,分析了半天,他说的还真对(废话)。