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 日