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

2023-12-20

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

换句话说,我需要的是:

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

我们的源到源转换引擎,DMS 软件再造工具包 https://www.semanticdesigns.com/Products/DMS/DMSToolkit.html?site=StackOverflow, 以其C++17前端 https://www.semanticdesigns.com/Products/FrontEnds/CppFrontEnd.html?site=StackOverflow可以用来做到这一点。

DMS可以接受显式的源到源转换规则 https://www.semanticdesigns.com/Products/DMS/DMSRewriteRules.html?site=StackOverflow.

单独的规则写为

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++ 代码的块(树)。 \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 副本进行清理代码。 (或者,可以在第一个或最后一个副本块上使用类似于 Duff 的设备 [在对 OP 问题的评论中提到] 的设备)。

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

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

所以使用DMSjust去做这个once可能没有很好地利用你的时间。如果您必须重复地自动执行此操作,或者在大型代码库上可靠地执行更复杂的操作,那么这是有意义的。我的两分钱。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

自动展开并输出C/C++代码 的相关文章

随机推荐