ROSE 编译器框架/抽象句柄
这项工作用于自动调优以及其他将源代码引用作为接口一部分传递的工具。
- 它本质上定义了创建字符串以唯一标识源代码中语言结构的方法
- 任何工具都可以找到 AST 中相应的节点,并为您执行目标分析或转换。
抽象句柄支持以下用于指定语言结构的形式
- 源文件位置信息,包括路径、文件名、行号和列号等。来自 http://www.gnu.org/prep/standards/html_node/Errors.html 的 GNU 标准源位置提供了一些示例。
- 源文件中指定语言结构的全局或局部编号(例如,全局范围内第二个“do”循环)。该文件本身使用抽象句柄(通常由文件名生成)指定。
- 结构的全局或局部名称。某些语言结构(例如文件、函数定义和命名空间)具有可作为其在上下文中的句柄的名称。
- 特定于语言的标签机制。这些包括 Fortran 中的命名结构、Fortran 中的编号标签以及 C 和 C++ 中的语句标签等。
除了人类可读的形式外,编译器和工具还可以为语言结构生成内部 ID。编译器/工具开发人员有责任提供一种将内部表示转换为人类可读格式的方法。
抽象句柄可以具有任何人类可读或机器生成的格式。句柄可以单独使用或与其他句柄组合使用来指定语言结构。句柄也可以从一种形式转换为另一种形式(例如,从特定于编译器的形式转换为相对于源位置的人类可读形式;文件名、行号等)。抽象句柄可以具有不同的生命周期,具体取决于其用途和实现。如果抽象句柄用于引用将在一个或多个不同工具的多次执行中优化的语言结构,则可能需要它持久化。而抽象句柄可能仅在单个执行中用于优化的目的而内部生成(例如,编译器中的优化)。
抽象句柄的典型用例可能是性能工具识别函数中的一组计算密集型循环,并构建引用这些特定循环的抽象句柄。然后将抽象句柄传递给第二个工具,该工具可能会分析源代码和/或二进制可执行文件以评估计算成本是否合理,或者是否存在优化的可能性。抽象句柄的具体目标是支持 DOE SciDAC PERI 项目中的自动调优研究中使用的各种工具中使用和/或开发的这类用途。
抽象句柄可能的语法可能是
- 句柄是单个句柄项,或由 :: 或其他分隔符分隔的它们的链接
handle ::= handle_item | handle ’::’ handle_item
- 每个句柄项都包含 construct_type 和一个指定符。或者它可以是任何形式的编译器生成的 ID。
handle_item ::= construct_type specifier | compiler_generated_handle
- 构造类型是特定于实现的。实现可以支持合法构造的子集或所有构造。我们在此定义了一组最小的常见构造类型名称,并将根据需要扩展此列表。
construct_type ::= Project|SourceFile|FunctionDeclaration|ForStatement|...
- 指定符用于定位特定构造,例如:<name, "foo">
specifier::= ’<’ specifier_type ’,’ specifier_value ’>’
- 指定符类型的标记可以是名称、位置、编号、标签等。指定符类型对于避免指定符值歧义是必要的,因为否则相同的数值可能会被解释为不同的指定符类型
specifier_type::= name | position | numbering | label
- 指定符的可能值
specifier_value::= string_lit|int_lit|position_value| label_value
- 标签可以是整数或字符串
label_value::= int_lit | string_lit
- 开始和结束源行和列信息
例如:13.5-55.4、13、13.5、13.5-55
position_value:: = line_number[ ’.’ column_number][ ’-’ line_number[ ’.’ column_number]]
- 整数:一个或多个数字
int_lit ::= [0-9]+
- 字符串值:以字母开头,后面跟零个或多个字母或数字
string_lit ::= [a-z][a-z0-9]*
抽象句柄从根本上来说是独立于编译器和工具的,但是为了阐明这些概念,提供有意义的示例,我们提供了一个在 ROSE 中的参考实现。源文件位于 ROSE 发行版的 src/midend/abstractHandle 中。一个通用接口(abstract handle.h 和 abstract handle.cpp)提供了数据结构和操作,用于使用源文件位置、编号或名称操作抽象句柄。任何编译器和工具都可以使用相同的接口拥有自己的实现。
使用该接口的 ROSE 适配器(roseAdapter.h 和 roseAdapter.cpp)作为实现的最大能力的具体实现(在源到源编译器中)。
下图显示了一个输入源文件。
/∗ test input for generated abstract handles ∗/ int a[100][100][100]; void foo() { int i,j,k; for (i=0;i++;i<100) for (j=0;j++;j<100) for (k=0;k++;k<100) a [ i ] [ j ] [ k]= i+j+k ; for (i=0;i++;i<100) for (j=0;j++;j<100) for (k=0;k++;k<100) a [ i ] [ j ] [ k]+=5; }
下图显示了使用 ROSE 生成输入源文件中循环的抽象句柄的代码。
/∗ Example code to generate abstract handles for language constructs by Liao, 10/6/2008∗/ #include “rose.h” #include <iostream> #include “abstract_handle.h” #include “roseAdapter.h” #include <string.h> using namespace std ; using namespace AbstractHandle ; // a global handle for the current file static abstract handle∗ file handle = NULL; class visitorTraversal : public AstSimpleProcessing { protected: virtual void visit (SgNode∗ n); }; void visitorTraversal :: visit (SgNode∗ n) { SgForStatement∗ forloop = isSgForStatement(n); if (forloop) { cout<<”Creating handles for a loop construct...”<<endl; // Create an abstract node abstract node∗ anode= buildroseNode(forloop ); // Create an abstract handle from the abstract node // Using source position specifiers by default abstract handle ∗ ahandle = new abstract handle (anode ); cout<<ahandle−>toString()<<endl ; // Create handles based on numbering specifiers within the file abstract handle ∗ bhandle = new abstract handle (anode , e_numbering , file_handle ); cout<<bhandle−>toString()<<endl<<endl ; } } int main(int argc, char ∗ argv[]) { // Initialize and check compatibility. See Rose:: initialize ROSE INITIALIZE; SgProject ∗project = frontend (argc , argv ); // Generate a f i l e handle abstract node ∗ file node = buildroseNode((project−>get fileList())[0]); file handle = new abstract handle(file node); // Generate handles for language constructs visitorTraversal myvisitor ; myvisitor.traverseInputFiles(project ,preorder); // Generate source code from AST and c a l l the vendor ’ s return backend( project ); }
抽象句柄构造函数从抽象节点生成句柄,这些抽象节点使用 ROSE AST 节点实现。默认情况下使用源位置来生成句柄项。当源位置信息不可用时,使用名称或编号代替。构造函数还可以用于使用指定的句柄类型(示例中的编号句柄)来生成句柄项。下图是显示为循环生成的句柄的输出。
Creating handles for a loop construct . . . Project<numbering,1>::FileList<numbering,1>::SourceFile<name,/export/tmp.rose−mg r/jenkins/edg4x/workspace/release−ROSE−docs−weekly/tutorial/inputCode AbstractHandle1 .cpp>::ForStatement<position ,7.3−10.25> Project<numbering,1>::FileList<numbering,1>::SourceFile<name,/export/tmp.rose−mg r/jenkins/edg4x/workspace/release−ROSE−docs−weekly/tutorial/inputCode AbstractHandle1 . cpp >:: ForStatement<numbering ,1> Creating handles for a loop construct . . . Project<numbering,1>::FileList<numbering,1>::SourceFile<name,/export/tmp.rose−mgr/jenkins/edg4x/workspace/release−ROSE−docs−weekly/tutorial/inputCode AbstractHandle1 .cpp>::ForStatement<position ,8.5−10.25> Project<numbering,1>::FileList<numbering,1>::SourceFile<name,/export/tmp.rose−mg r/jenkins/edg4x/workspace/release−ROSE−docs−weekly/tutorial/inputCode AbstractHandle1 . cpp >:: ForStatement<numbering ,2> Creating handles for a loop construct . . . Project<numbering,1>::FileList<numbering,1>::SourceFile<name,/export/tmp.rose−mgr/jenkins/edg4x/workspace/release−ROSE−docs−weekly/tutorial/inputCode AbstractHandle1 .cpp>::ForStatement<position ,9.7−10.25> Project<numbering,1>::FileList<numbering,1>::SourceFile<name,/export/tmp.rose−mg r/jenkins/edg4x/workspace/release−ROSE−docs−weekly/tutorial/inputCode AbstractHandle1 . cpp >:: ForStatement<numbering ,3> 24 Creating handles for a loop construct . . . Project<numbering,1>::FileList<numbering,1>::SourceFile<name,/export/tmp.rose−mgr/jenkins/edg4x/workspace/release−ROSE−docs−weekly/tutorial/inputCode AbstractHandle1 .cpp>::ForStatement<position ,12.3−15.22> Project<numbering,1>::FileList<numbering,1>::SourceFile<name,/export/tmp.rose−mg r/jenkins/edg4x/workspace/release−ROSE−docs−weekly/tutorial/inputCode AbstractHandle1 . cpp >:: ForStatement<numbering ,4> Creating handles for a loop construct . . . Project<numbering,1>::FileList<numbering,1>::SourceFile<name,/export/tmp.rose−mgr/jenkins/edg4x/workspace/release−ROSE−docs−weekly/tutorial/inputCode AbstractHa 36 ndle1 .cpp>::ForStatement<position ,13.5−15.22> Project<numbering,1>::FileList<numbering,1>::SourceFile<name,/export/tmp.rose−mg r/jenkins/edg4x/workspace/release−ROSE−docs−weekly/tutorial/inputCode AbstractHandle1 . cpp >:: ForStatement<numbering ,5> Creating handles for a loop construct . . . Project<numbering,1>::FileList<numbering,1>::SourceFile<name,/export/tmp.rose−mgr/jenkins/edg4x/workspace/release−ROSE−docs−weekly/tutorial/inputCode AbstractHandle1 .cpp>::ForStatement<position ,14.7−15.22> Project<numbering,1>::FileList<numbering,1>::SourceFile<name,/export/tmp.rose−mg r/jenkins/edg4x/workspace/release−ROSE−docs−weekly/tutorial/inputCode AbstractHa ndle1 . cpp >:: ForStatement<numbering ,6>
提供第三个示例来演示如何将抽象接口与任何其他工具一起使用,这些工具在支持的语言结构及其相关性方面可能功能较少,与编译器相比。假设一个工具在任意源文件中的简单 for 循环上操作(此示例中未显示输入文件)。这样的工具可能有一个内部数据结构来表示循环;例如,下一张图中给出的数据结构。
/∗ A toy loop data structure demonstrating a thin client of abstract handles: ∗ A simplest loop tool which keeps a tree of loops in a file ∗/ #ifndef my loop INCLUDED #define my loop INCLUDED #include <string> #include <vector> class MyLoop { public : std::string sourceFileName; size t line number ; std : : vector<MyLoop∗> children ; MyLoop∗ parent ; }; #endif
我们将展示如何使用特定于工具的循环数据结构来生成抽象句柄并输出为字符串,这些字符串可供使用抽象句柄的其他工具使用(这些工具将通过读取字符串生成抽象句柄)。
使用建议的抽象句柄接口的适配器(loopAdapter.h 和 loopAdapter.cpp)在 src/midend/abstractHandle 中给出。它为该接口提供了简单循环的具体实现,并添加了一个节点来支持文件节点(与编译器的全功能 IR 相比,文件节点是针对没有数据结构支持文件的工具的额外细节)。测试程序在下图中给出。
#include <iostream> #include <string> #include <vector> #include ”abstract handle .h” #include ”myloop . h” ”loopAdapter .h” using namespace std ; using namespace AbstractHandle ; 10 int main() { //−−−−−−−−−−−−−Preparing the internal loop representation−−−−−−−−− // declare and initialize a list of loops using MyLoop // The loop tool should be able to generate its representation from // source code somehow. We fill it up manually here. vector <MyLoop∗ > loops; MyLoop loop1 , loop2 , loop3; loop1.sourceFileName=”file1.c”; loop1.linenumber = 7; loop1.parent = NULL; loop2.sourceFileName=”file1.c”; loop2.linenumber = 8; loop2.parent = &loop1; loop1.children.pushback(&loop2 ); loop3.sourceFileName=”file1.c”; loop3.linenumber = 12; loop3.parent=NULL; loops.pushback(&loop1); loops.pushback(&loop3); //−−−−−−−−−−−−−−−−−− using abstract handles −−−−−−−−−−−−− //Generate the abstract handle for the source file fileNode∗ filenode = new fileNode(”file1 .c”); filenode−>setMLoops(loops); abstract handle∗ file handle = new abstract handle(filenode); cout<<”Created a file handle:”<<endl<<file handle−>toString()<<endl; //Create a loop handle within the f i l e using numbering info. abstract node∗ loop node1 = new loopNode(&loop1); abstract handle∗ loop handle1 = new abstract handle(loop node1 ,e_numbering , file_handle); cout<<”Created a loop handle:”<<endl<<loop handle1−>toString()<<endl; //Create another loop handle within a file using its source position information string input1(”ForStatement<position ,12>”); abstract handle∗ loop handle2 = new abstract handle ( file_handle , input1 ); cout<<”Created a loop handle:”<<endl<<loop handle2−>toString()<<endl; //Create yet another loop handle within a loop using its relative numbering information string input2(”ForStatement<numbering,1>”); abstract handle∗ loop handle3 = new abstract handle(loop handle1 ,input2); cout<<”Created a loop handle:”<<endl<<loop handle3−>toString()<<endl; return 0 ; }
同样,它首先创建一个顶级文件句柄。然后使用其相对编号信息在文件句柄中创建一个循环句柄(loop handle1)。loop handle2 是使用文件位置信息从其字符串格式创建的(使用 GNU 标准文件位置语法)。loop handle3 使用其在 loop handle1 中的相对编号信息。
程序的输出显示在下面的图片中。它演示了生成的字符串来表示工具操作的任意代码中的抽象句柄。通过另一个工具读取生成的字符串表示来生成指向相同源代码语言结构的抽象句柄,从而实现互操作性。
bash −3.00: ./testMyLoop Created a file handle: SourceFile<name, file1 .c> Created a loop handle : SourceFile<name, file1 .c>::ForStatement<numbering,1> Created a loop handle : SourceFile<name, file1 .c>::ForStatement<position ,12> Created a loop handle : SourceFile<name, file1 .c>::ForStatement<numbering,1>::ForStatement<numbering,1>
我们给出一些使用上述语法表示语言句柄的示例。规范的 AST 节点类型名称用作结构类型名称。其他实现可以使用他们自己的结构类型名称。
- 一个仅包含一个句柄项的文件句柄
SourceFile<name,"/home/PERI/test111.f">
- 一个使用命名句柄项的函数句柄,与一个也使用名称的父句柄组合在一起
SourceFile<name,"/home/PERI/test111.f">::FunctionDeclaration<name,"foo”>
- 一个使用源位置的函数句柄(一个从文件中的第 12 行第 1 列到第 30 行第 1 列开始的函数)
SourceFile<name,"/home/PERI/test111.f">::FunctionDeclaration<position,"12.1-30.1">
- 一个使用编号的函数句柄(文件中的第一个函数定义)
SourceFile<name,/home/PERI/test111.f">::FunctionDeclaration<numbering,1>
- 一个使用源位置的返回语句(第 100 行的返回语句)
SourceFile<name,/home/PERI/test222.c>::ReturnStatement<position,"100">
- 一个使用编号信息的循环(函数 main() 中的第二个循环)
SourceFile<name,"/home/PERI/test222.c">::FunctionDeclaration<name,"main">::ForStatement<numbering,2>
- 一个使用编号信息的嵌套循环(函数 main() 中第二个循环内的第一个循环)
SourceFile<name,"/home/PERI/test222.c">::FunctionDeclaration<name,"main">:: ForStatement<numbering,2>::ForStatement<numbering,1>
概述输入代码第 12 行处的 for 循环
- ./outline -rose:outline:abstract_handle "ForStatement<position,12>" -c $(srcdir)/inputCode_OutlineLoop2.c
概述输入代码中名为 initialize() 的函数内的第二个 for 语句
- ./outline -rose:outline:abstract_handle "FunctionDeclaration<name,initialize>::ForStatement<numbering,2>" -c $(srcdir)/inputCode_OutlineLoop2.c -rose:output rose_inputCode_OutlineLoop2b.c
概述输入代码第 5 行处的语句
- ./outline -rose:outline:abstract_handle "Statement<position,5>" -c $(srcdir)/declarations.c
抽象句柄是支持多个工具交换对源代码的引用的低级机制。几个示例用于展示抽象句柄的不同功能。重要的是,抽象句柄的规范是工具无关的。提供了一个参考实现,并在 ROSE 编译器框架中公开提供。我们鼓励就该概念的优缺点进行讨论,以支持必须在它们之间传递对源代码的引用的工具的互操作性。这项工作预计是支持自动调整研究的基础设施的一小部分。
- 文档:ROSE 教程第 46 章:http://rosecompiler.org/ROSE_Tutorial/ROSE-Tutorial.pdf
- 头文件:https://github.com/rose-compiler/rose-develop/blob/master/src/midend/abstractHandle/abstract_handle.h
- 示例用法:https://github.com/rose-compiler/rose-develop/blob/master/projects/autoTuning/tests/Makefile.am
- http://rosecompiler.org/autoTuning.pdf 第 6.2 节解释了如何使用抽象句柄对指定的循环进行参数化循环变换。
- https://github.com/rose-compiler/rose-develop/blob/master/tests/nonsmoke/functional/roseTests/astInterfaceTests/loopCollapsing.C 一个接受抽象句柄的循环折叠工具
如何在您的工具中支持抽象句柄
#include "rose.h" #include <string> #include <iostream> #include "commandline_processing.h" using namespace std; using namespace AbstractHandle; int main(int argc, char * argv[]) { std::string handle; int factor =2; // command line processing //-------------------------------------------------- vector<std::string> argvList (argv, argv+argc); if (!CommandlineProcessing::isOptionWithParameter (argvList,"-rose:loopcollapse:","abstract_handle",handle, true) || !CommandlineProcessing::isOptionWithParameter (argvList,"-rose:loopcollapse:","factor",factor, true)) { cout<<"Usage: loopCollapsing inputFile.c -rose:loopcollapse:abstract_handle <handle_string> -rose:loopcollapse:factor N"<<endl; return 0; } // Retrieve corresponding SgNode from abstract handle //-------------------------------------------------- SgProject *project = frontend (argvList); SgStatement* stmt = NULL; ROSE_ASSERT(project != NULL); SgFilePtrList & filelist = project->get_fileList(); SgFilePtrList::iterator iter= filelist.begin(); for (;iter!=filelist.end();iter++) { SgSourceFile* sfile = isSgSourceFile(*iter); if (sfile != NULL) { // prepare a file handle first abstract_node * file_node = buildroseNode(sfile); ROSE_ASSERT (file_node); abstract_handle* fhandle = new abstract_handle(file_node); ROSE_ASSERT (fhandle); // try to match the string and get the statement handle std::string cur_handle = handle; abstract_handle * shandle = new abstract_handle (fhandle,cur_handle); // it is possible that a handle is created but no matching IR node is found if (shandle != NULL) { if (shandle->getNode() != NULL) { // get SgNode from the handle SgNode* target_node = (SgNode*) (shandle->getNode()->getNode()); ROSE_ASSERT(isSgStatement(target_node)); stmt = isSgStatement(target_node); break; } } } //end if sfile } // end for if (stmt==NULL) { cout<<"Cannot find a matching target from a handle:"<<handle<<endl; return 0; } //-------------------------------------------------- if (isSgForStatement(stmt)) { bool result=false; SgForStatement *target_loop = isSgForStatement(stmt); result = SageInterface::loopCollapsing(target_loop, factor); ROSE_ASSERT(result != false); } // Generate source code from AST and call the vendor's compiler return backend(project); }
要引用抽象句柄工作,请使用以下论文,其中首次发布了句柄
- Chunhua Liao, Daniel J. Quinlan, Richard Vuduc 和 Thomas Panas, 有效的源到源概述以支持全程序经验优化, 第 22 届并行计算语言和编译器国际研讨会 (LCPC), 美国特拉华州纽瓦克。2009 年 10 月 8 日至 10 日