gcc - 自动展开并输出C/C++代码

标签 gcc compiler-construction llvm cpu-architecture icc

我正在做一个实验,第一步是展开循环(从 C/C++)十几次(例如:10、50 等)并输出 C/C++ 展开代码。我可以使用任何工具来自动展开此类展开吗?

换句话说,我需要的是:

C/C++ source/loop --->> TOOL (Unroll by X) ---->  Unrolled C/C++ source/loop

最佳答案

我们的源到源转换引擎, DMS Software Reengineering Toolkit , 及其C++17 front end可以用来做到这一点。

DMS 可以接受 explicit source-to-source transformation rules .

各个规则写为

rule rule_name(metavariables_with_syntax_categories)
:syntax_category->syntax_category
= left_hand_side_pattern_to_match 
-> right_hand_side_replacement_after_substitution

下面我提供了一个非常接近目标的(未经测试的)集合。这些直接受到用于展开循环的经典编译器优化的启发。

你看到的“...”里面的...表示“(C++语法)...”;这些是“这里是域文本元引号,而不是 C++ 字符串引号。 “...”内的\foo 表示元变量 foo,它代表 C++ 代码的一个 block (树)。 \bar(...\,...) 表示“在 ... 上调用元函数 bar”,请注意“元逗号”拼写为\,并且元括号 ( ) 用于区分元函数与域(“C++”)语法。 有关此类规则语法的更多详细信息,请参阅链接。

未加引号的模式 UNROLL 和 ReplaceIbyEXP 定义“元函数”,可以将其视为应用更多转换的意图。

这里 UNROLL 捕获了我们想要重复一段代码 n 次的想法。有两个(有效递归)规则来实现此概念,一个用于“重复零次”的基本情况,生成一个空语句列表,另一个生成代码块,然后重复 n-1 次。 ReplaceIbyEXP 然后调整我在复制的代码块中使用的索引。

external pattern ReplaceIbyEXP(s:statements,i:IDENTIFIER,r:expression):statements;

pattern UNROLL_1(s:statements,i:IDENTIFIER,k:INT_LITERAL,c:INT_LITERAL)
  :statements->statements;

rule UNROLL_1(s:statements,i:IDENTIFIER,d:INT_LITERAL,c:INT_LITERAL)
  :statements->statements
  = UNROLL(s,i,d,c) -> ";" if c=="0";

rule UNROLL_N((s:statements,i:IDENTIFIER,d:INT_LITERAL,c:INT_LITERAL)
  :statements->statements
  = UNROLL(s,i,d,c)
  -> "\ReplaceIbyEXP\(\s\,\i\,(\i+\d)\)
      \UNROLL\(\s,\i,\add\(\d\,1\),\subtract\(\c\,1\))" if c!="1";

rule UNROLL_FOR_k(i:IDENTIFIER,s:statements,limit:INT_LITERAL)
  :statements->statements
  = "for (\i=0;\i<\limit;\i++) { \s }"
  -> "for (\i=0;\i<\limit;\i+=k) { \UNROLL(\s\,\i\,0,k) }"

这段代码有很多问题需要解决:

  • 不表示ReplaceIbyEXP的实现;目前,需要 通过调用 DMS 的过程(“PARLANSE”)部分(“外部”)来执行树遍历并用提供的子表达式替换匹配标识符的每个实例来实现。 在程序部分,这些已经是树,可以使用简单的“AST:EqualNode”和“AST:ReplaceSubtree”来实现它。这可能是另外 20 行 PARLANSE 代码。

  • 它不处理循环边界不是 k 倍数的情况。这意味着需要有 UNROLL_FOR_k 的变体,一种情况是循环边界是倍数(即此处提供的),另一种情况不是倍数。然后需要生成一个包含 k 个副本的展开循环,然后是对代码的 limit modulk 副本进行清理代码。 (或者,可以在第一个或最后一个副本 block 上使用 Duff 的设备 [在对 OP 问题的评论中提到] 之类的设备)。

  • 人们可能想从“外部”提供 k。使用另一个外部模式来获取它可以轻松实现。

现在,学习使用像 DMS 这样的引擎相当复杂,部分原因是您正在处理已经非常复杂的 C++,部分原因是 DMS 的机制必须能够处理 C++ 引发的所有小错误。 [出于同样的原因,Clang 同样难以应用,但它不提供模式驱动的转换机制]。

因此,仅使用 DMS 来执行此操作一次可能不太浪费您的时间。如果您必须重复地自动执行此操作,或者在大型代码库上可靠地执行更复杂的操作,那么这是有意义的。我的两分钱。

关于gcc - 自动展开并输出C/C++代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23740034/

相关文章:

compiler-construction - 什么是绝对代码,为什么在编译时就知道它?

c - C 中泛型函数与函数指针数组相比有何缺点?

linux - 加载共享库时,它是否可能引用当前二进制文件中的某些内容?

c - C 中迭代次数少的段错误

c - "sizeof (char[0])"怎么用 GCC 编译得很好

iphone - XCode4 不显示 "C/C++ Compiler Version"选项

c++ - XCode 中的 LLVM-GCC ASM 到 LLVM

进入库时更改结构值

c# - 条件运算符会感到困惑,但为什么呢?

c++ - LLVM 从 Value* 返回常量整数