1,ROSE安装的回顾
mac上面的rose安装最终以失败而告终,原因是EDG包找不到,虽然昨天起rose官网已经恢复正常了。
现在理解了为什么下载的rose安装包文件名清楚的写道“withou-EDG”。EDG是c/c++的前端分析器,它负责生成语法树,而Sage3是在这个语法树的基础上进行了自己的包装。
EDG以二进制包的形式提供给rose使用,它和GCC版本、操作系统、ROSE版本有关系,所以在make的最后阶段,会根据这些信息去rose官网上找对应的EDG二进制包。
虽然不一定完整,但是EDG二进制包在这里可以看到https://github.com/rose-compiler/edg-binaries
当然,如果向EDG开发团队申请科研license,可以拿到edg源码包,这样就不用找特定类型的binary了。不过有点麻烦,我还是继续用我的rhel版本。
2,rose的参考材料介绍
1)rose tutorial
里面有大量的示例程序展示如何调用rose的接口,且在程序的编译目录下(注意,是编译目录,而不是最后的安装目录)有个tutorial文件夹,里面有这些示例程序的源代码。
2)rose user manual
和tutorial不同,user manual侧重于rose的实现介绍,对用户更加深入了解rose的实现有帮助。
在这里,对tutorial和user manual里面前7章的内容进行部分介绍,这也记录着我的学习历程。
3,AST(抽象语法树)的直观理解
以上两幅图是针对一个最简单的a[i][j]=1.0/i+j;的二重循环赋值程序,使用dotGenerator得到的。这个工具详见tutorial chapter3。
第一幅图,直观的认识是:一个程序,全局域里面包括两个定义,一个是main函数(右子树),一个是全局变量的定义(左子树)。
第二幅图,直观的认识是:对于for循环,包括四个子树,最左边的时变量i的初始化条件,第二个是变量i的终止条件,第三个是变量i的自增条件,第四个是for循环内部的程序(basic block)。
我们需要对语法树进行操作,某个语法树就和某个程序对应。最后我们的目标肯定是通过修改AST,达到生成优化过后的新程序的目的。
根据张立博师兄的说法,修改语法树肯定不是我们一个节点一个节点的改,而是通过ROSE提供的接口进行修改。做某些语法树修改如果一个节点一个节点的改肯定特别麻烦,而且容易出错。
ROSE的AST图结构帮助我们理解编译器是如何理解源程序的。
每个圈圈代表ROSE的IR(intermediate representation)节点,那串英文是这个结构名称,上面代表前序遍历的进出序列时间,下面表示有几个子节点。指针地址在最下面。每个节点都是一个C++类。
3)编译运行程序
在编译目录(非下载目录,非安装目录)的exampleTranslators/documentedExamples/simpleTranslatorExample目录下,有个exampleMakefile,这可以作为编译自己程序的样例makefile,很简单,40多行。但是有一个问题,里面的libtool是做什么的?这个下一次blog说明一下。(问题1)
4)Query操作
据userManual里的Chapter6,query分为三种类型:
1,query AST中的subTree。(且如果函数参数中给定NodeQuery::ChildrenOnly,则只遍历直接后继结点;否则遍历子树中的所有节点)
2,query AST中的node list
3,query memory pool
在tutorial chapter7中,有两个例子,一个是简单的querySubTree(tutorial/queryLibraryExample.C),一个是对querySubTree的结果进行简单的处理和query memory pool处理(tutorial/nestedQueryExample.C)。
第一个例子的核心程序如下:
13 // Build a list of functions within the AST
14 Rose_STL_Container<SgNode*> functionDeclarationList = NodeQuery::querySubTree (project,V_SgFunctionDeclaration);
15
16 int counter =0;
17 for (Rose_STL_Container<SgNode*>::iterator i = functionDeclarationList.begin(); i != functionDeclarationList.end(); i++)
18 {
19 // Build a pointer to the current type so that we can call the get_name() member function.
20 SgFunctionDeclaration* functionDeclaration = isSgFunctionDeclaration(*i);
21 ROSE_ASSERT(functionDeclaration !=NULL);
22
23 // DQ (3/5/2006): Only output the non-compiler generated IR nodes
24 if ( (*i)->get_file_info()->isCompilerGenerated() ==false)
25 {
26 // output the function number and the name of the function
27 printf ("Function #%2d name is%s at line %d \n",
28 counter++,functionDeclaration->get_name().str(),
29 functionDeclaration->get_file_info()->get_line());
30 }
31 else
32 {
33 // Output something about the compiler-generated builtin functions
34 printf ("Compiler-generated (builtin) function #%2d name is%s\n",
35 counter++,functionDeclaration->get_name().str());
36 }
37 }
对一个简单的stecil计算程序(只有main函数),生成的结果惊人:里面有420个builtin function,还有107个getw,putw, fseek之类的function,最后才是main function
为什么是这样呢?这个下一个blog解释。(问题2)
这里需要仔细介绍下各个数据结构:
#define Rose_STL_Container std::vector |
http://fossies.org/dox/rose-0.9.5a-without-EDG-20584/index.html
里面有各个类的描述,也有类图的描述,很不错!
v_sgfunctiondeclaration=382是enum variantT里定义,在cxx_grammar.h里面定义。
sgFunctionDeclaration是 doxgen里面可以查到的class定义,里面有get_file_info和get_name等定义。
queryMemoryPool意思可能和querySubTree(project,)类似。目前理解是这样。。
5)Traverse操作
这里面有5个Ast*Processing类,每个类里面都有三种不同的遍历函数:
traverse, traverseInputFiles, traverseWithinFile
a)第一个例子,也是最简单的例子,是tutorial/visitorTraversal.C
这个例子是重写了AstSimpleProcessing类里面的visit函数,判断当前signed是否是for循环。
但是如果添加一句,cout<<n->class_name()<<endl;并和dotGenerator得到的图进行比对发现:
打印的顺序就是第一次进入该节点的时间戳,同时,打印的点的class_name和dotGenerator一致。
这里就又出现类似问题2的问题,simpleProcessing里面为什么得到的点这么少,而dotGeneratorWholeASTGraph里面得到的点又是什么(问题3)。
b)prePostTraversal.c
preOrderVisit这个虚函数表示前序遍历到这个点进行的操作。PostOrderVisit这个虚函数表示后序遍历到这个节点进行的操作。
例子中,对于loop 结构,正好前序遍历作为enter loop操作,后序遍历作为leaving loop操作。
c)astTopDownProcessing(inheritedAttributeTraversal.C)
相当于在astSimpleProcessing里面的visit函数里多了个参数,叫InheritedAttribute。
这个类是自定义的,按照前序遍历没每访问一个点就调用这个evaluateInheritedAttribute函数,通过这个自定义类在遍历中传递参数。
d)astBottomUpProcessing(synthesizedAttributeTraversal.C)
需要实现的虚函数是evaluateSynthesizedAttribute(SgNode* astNode, synthesizedAttributesList synList)
需要注意的是第二个参数,它是子节点的synthesizedAttribute的vector,用一个iterator来进行遍历。
这样,每个节点就可以进行bottomup操作。理论上说,遍历顺序应该是从下往上,递归的进行遍历。但打印遍历顺序来看,后面几个的遍历很符合。
但遍历的总数特别大,不知道为什么。
e)astTopDownBottomUpProcessing()
这里面需要实现的函数是evaluateInheritedAttribute和evaluateSynthesizeAttribute两个,
根据Tutorial和User manual里面的两个例子,一般的用法是对于某个点sgNode*n,evaluateInheritedAttribute算出从上到下继承到的数据,
evaluateSynthesizeAttribute算出从下至上合成的数据;但最关键的是,前一个函数有两个参数而后一个函数有三个参数。
这也意味着后一个函数可以用前一个函数计算得到的结果(参数给定),而不能相反。
陆陆续续写了一周,对nodeQuery和ASTTraverse进行了比较全面的介绍。下一步就是进行AST的transformation了,当然下一个blog会回答这里面遗留的若干问题。
分了?!不觉得是这样但又好像已经是这样。。这周的思路乱的很,很难长时间静心学术,哎。。
也许这周末会有好结果,也许学术感情双丰收呢!加油!!求给力!!!