ROSE 編譯器框架/宣告移動工具
該工具會將變數宣告移動到其最內部可能的可用作用域。
對於一個宣告,找到可以將其移動到的最內部作用域,而不會破壞程式碼的原始語義。
- 對於一個單一的使用位置,將其移動到最內部作用域。
- 對於多個使用情況,如果中間沒有變數重用,則可能需要複製宣告並移動到兩個作用域,否則,將宣告移動到多個使用的最內部公共作用域。
該工具作為 ROSE 編譯器的一部分發布。請按照以下說明安裝 ROSE(版本 0.9.9.123 或更高版本)
- 安裝:在配置期間,您可能需要指定一個字首路徑,例如 –prefix=/home/youraccount/opt/rose-0.9.9.123。然後,按照 ROSE 安裝指南構建並安裝 ROSE。
為了節省時間,您只需構建/安裝 librose 和您感興趣的工具。注意在您的構建樹中
- 輸入 “make install-core -j8” # 這將構建 librose.so 和一些核心工具
或者,您可以安裝所有內容,這將花費更長時間
- 輸入 make install -j8 以安裝核心 ROSE 庫和一些預構建工具。
在構建/安裝 ROSE 的過程中,將建立一個名為 moveDeclarationToInnermostScope 的可執行檔案。該工具將安裝到 –prefix=ROSE 安裝路徑指定的路徑。使用者可以使用它來處理他們的程式碼。
下一步是設定環境變數以搜尋 ROSE 可執行檔案(包括此移動工具)和共享庫的路徑。假設您使用的是 bash,請將以下行放入一個檔案(例如 set.rose)並對其進行原始碼化(輸入 source set.rose)
ROSE_INS=/home/youraccount/opt/rose--0.9.9.123 export ROSE_INS PATH=$ROSE_INS/bin:$PATH export PATH LD_LIBRARY_PATH=$ROSE_INS/lib:$LD_LIBRARY_PATH export LD_LIBRARY_PATH
現在,您可以使用此工具轉換您的程式碼。假設您有一個順序檔案:file.c,只需輸入 moveDeclarationToInnermostScope -c file.c。將生成一個輸出檔案 rose file.c。
要處理多個檔案,您需要更改您的 makefile 以使用 moveDeclarationToInnermostScope 作為編譯器來編譯您的程式碼。該工具將首先轉換您的程式碼並生成 rose_originalFile.C,然後呼叫後端編譯器(通常是 GCC/G++)來完成編譯。
翻譯器接受以下選項
- -rose:merge_decl_assign 將合併移動後的宣告與緊隨其後的賦值。
- -rose:aggressive : 啟用積極模式,該模式將移動具有初始化器的宣告,並跨越迴圈邊界。如果移動跨越迴圈邊界,則會發出警告訊息。如果沒有此選項,該工具僅移動沒有初始化器的宣告以確保安全。
- -rose:debug,預設情況下在測試中啟用。將生成一些用於除錯目的的變數作用域樹的點圖檔案。
- -rose:keep_going 將盡可能忽略斷言(當前在複雜的 for 迴圈初始化語句列表上跳過斷言)。如果沒有此選項,該工具將在斷言失敗時停止。
- -rose:identity 將關閉任何轉換並充當身份翻譯器。在除錯目的中很有用。
- -rose:trans-tracking 將啟用轉換跟蹤模式,顯示移動/合併宣告的源語句
moveDeclarationToInnermostScope --help 的基本輸出
MOVEDECLARATIONTOINNERMOSTSCOPE(1) ROSE Command-line Tools MOVEDECLARATIONTOINNERMOSTSCOPE(1)
Name
moveDeclarationToInnermostScope - This tool moves variable declarations to their innermost possible scopes
Synopsis
moveDeclarationToInnermostScope switches files...
Description
This tool is designed to help parallelizing code by moving variable declarations into their innermost possible scopes (essentially
making many of them private). As a result, less variables need to be shared.
...
The move tool switches
These switches control the move tool.
--[rose:]aggressive
Enable aggressive mode: declarations with initializers will be moved.
--[rose:]debug
Enable the debugging mode.
--[rose:]identity
Enable acting like an identity translator, not doing any transformation at all.
--[rose:]keep_going
Allow the tool to proceed without being stopped by assertions.
--[rose:]merge_decl_assign
After the move, further merge the moved naked variable declaration (without initialization) with a followed variable assignment.
--[rose:]trans-tracking
Enable tracking of transformation steps.
ROSE's built-in switches
--rose:help
Show the old-style ROSE help.
0.9.9.123 Thursday October 12 13:51:28 2017 MOVEDECLARATIONTOINNERMOSTSCOPE(1)
原始碼
測試
- 在 buildtree/tests/nonsmoke/functional/moveDeclarationTool 中輸入 “make move_diff_check”,定義在
- https://github.com/rose-compiler/rose-develop/blob/master/tests/nonsmoke/functional/moveDeclarationTool/Makefile.am
- 測試輸入檔案位於 https://github.com/rose-compiler/rose-develop/tree/master/tests/nonsmoke/functional/moveDeclarationTool 下
- 28 個檔案進行基於 diff 的正確性檢查
- 202 個檔案用於基於 token 的 unparsing
對於以下輸入程式碼 Test.cc
void AccumulateForce(int *idxBound, int *idxList, int len,
double *tmp, double *force)
{
register int ii ;
register int jj ;
int count ;
int *list ;
int idx ;
double sum ;
for (ii=0; ii<len; ++ii) {
count = idxBound[ii+1] - idxBound[ii] ;
list = &idxList[idxBound[ii]] ;
sum = 0.0 ;
for (jj=0; jj<count; ++jj) {
idx = list[jj] ;
sum += tmp[idx] ;
}
force[ii] += sum ;
}
return ;
}
您可以執行移動工具,如下所示,以生成下面的 rose_Test.cc 輸出檔案
moveDeclarationToInnermostScope -rose:unparse_tokens -rose:merge_decl_assign -c Test.cc
關於此命令列,有幾點需要注意。moveDeclarationToInnermostScope 工具充當底層編譯器的前端,底層編譯器的命令列選項將被遵守。在這裡,我們還有一些 ROSE/工具特定的命令列選項。'-rose:unparse_tokens' 選項告訴 ROSE 在生成 rose_xxx.cc 輸出檔案時,要格外小心,以保留輸入原始檔的原始碼格式。'-rose:merge_decl_assign' 選項特定於重新作用域工具,並指示任何移動的宣告應該嘗試與目標作用域中預先存在的賦值語句合併。
輸出檔案將如下所示
void AccumulateForce(int *idxBound, int *idxList, int len,
double *tmp, double *force)
{
for (register int ii = 0; ii<len; ++ii) {
int count = idxBound[ii + 1] - idxBound[ii];
int *list = &idxList[idxBound[ii]];
double sum = 0.0;
for (register int jj = 0; jj<count; ++jj) {
int idx = list[jj];
sum += tmp[idx] ;
}
force[ii] += sum ;
}
return ;
}
看看上面轉換後的原始碼,有幾個值得注意的地方
- 宣告時關聯的任何限定符在宣告被移動時都會保留。
- 與 for 迴圈控制變數相關的宣告被移動到迴圈頭中。
- 由於存在 -rose:merge_decl_assign 命令列選項,賦值語句和宣告被合併。
為每個宣告構建作用域樹
- 節點:DS(宣告作用域)、IS(中間作用域)和 US(使用作用域)
- 邊:兩個作用域之間的父子關係
樹形狀屬性的情況
- 單條直線樹
- 單個底部使用作用域:將宣告移動到底部
- 多個使用作用域:修剪陰影使用作用域,將宣告移動到第一個使用作用域
- 樹的多個分支
- 分支兄弟節點之間有 LiveIn:將宣告移動到兄弟節點的父作用域。
- 兄弟節點之間沒有 LiveIn:將宣告移動到每個分支作用域
- 目標作用域的深度不相等:暫時移動到相等深度,迭代移動插入的宣告。工作列表演算法
相關原始碼
- Scope_Node* generateScopeTree(SgDeclarationStatement* decl, bool debug = false)
V1:工作列表演算法
- 初始工作列表 = 函式中的原始宣告
- while (!worklist.empty())
- decl = worklist.front(); worklist.pop();
- moveDeclarationToInnermostScope(decl, inserted_decls);
- worklist.push_back(每個 inserted_decls)
V2:專注於查詢目標作用域,因為不需要多次(迭代)宣告移動
- 如果我們知道要移動到的最終作用域,則可以一次性將聲明覆制移動到所有目標作用域
演算法 v2
- 分析:findFinalTargetScopes(宣告,&target_scopes)
- scope_tree_worklist.push(scope_tree);
- while (!scope_tree_worklist.empty())
- current_scope_tree = scope_tree_worklist.front(); …
- collectCandidateTargetScopes(decl, current_scope_tree);
- if (找到底層作用域) target_scopes.push_back(candidate)
- else scope_tree_worklist.push_back(candiate)
- 轉換
- if (target_scopes.size()>0)
- copyMoveVariableDeclaration(decl, target_scopes);
- if (target_scopes.size()>0)
main()
- exampleTraversal.traverseWithinFile (s_file, preorder); // 移動宣告
- visitorTraversal::visit()
- if (merge_decl_assign) collectiveMergeDeclarationAndAssignment (inserted_decls); // 將宣告與賦值一起移動
列表
- 目前使用的是保守的語法活性分析,我們正在將其改為使用更好的活性分析
- 該工具只移動在函式內宣告的區域性變數,不移動全域性變數。
- 移動全域性變數需要對多個原始檔進行全域性分析,以避免破壞原始語義。
- 此外,全域性變數通常在標頭檔案中宣告。轉換標頭檔案仍在進行中。