跳转到内容

ROSE 编译器框架/声明移动工具

来自维基教科书,开放世界中的开放书籍

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)

源代码和测试

[编辑 | 编辑源代码]

源代码

测试

示例使用

[编辑 | 编辑源代码]

对于以下输入代码 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:工作列表算法

[编辑 | 编辑源代码]

V1:工作列表算法

  • 初始工作列表 = 函数中的原始声明
  • while (!worklist.empty())
    • decl = worklist.front(); worklist.pop();
    • moveDeclarationToInnermostScope(decl, inserted_decls);
    • worklist.push_back(每个 inserted_decls)

V2:分离分析和移动

[编辑 | 编辑源代码]

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);


调用堆栈

[编辑 | 编辑源代码]

main()

  • exampleTraversal.traverseWithinFile (s_file, preorder); // 移动声明
    • visitorTraversal::visit()
  • if (merge_decl_assign) collectiveMergeDeclarationAndAssignment (inserted_decls); // 将声明与赋值一起移动

限制和正在进行的工作

[编辑 | 编辑源代码]

列表

  • 目前使用的是保守的语法活性分析,我们正在将其改为使用更好的活性分析
  • 该工具只移动在函数内声明的局部变量,不移动全局变量。
    • 移动全局变量需要对多个源文件进行全局分析,以避免破坏原始语义。
    • 此外,全局变量通常在头文件中声明。转换头文件仍在进行中。
华夏公益教科书