我正在做一个实验,第一步是展开一个循环(来自C / C ++)十几次(例如:10,50等)并输出C / C ++展开的代码。是否有任何工具可用于自动化这种展开?
换句话说,我需要的是:
C/C++ source/loop --->> TOOL (Unroll by X) ----> Unrolled C/C++ source/loop
答案 0 :(得分:2)
我们的源到源转换引擎, 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 ++代码的一块(树)。 \ 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”)部分(“ external”)来实现树遍历,并用提供的子表达式替换匹配标识符的每个实例来实现。 在程序部分中,这些已经是树,可以使用简单的“ AST:EqualNode”和“ AST:ReplaceSubtree”来实现它。这可能是另外20行的PARLANSE代码。
它不能处理循环边界不是k的倍数的情况。这意味着需要有UNROLL_FOR_k的变体,其中一个变量的循环绑定是一个倍数(这是此处提供的变量),而不是一个倍数。然后,需要生成k个副本的展开循环,然后生成限制代码的k个副本的限制的清除代码。 (或者,可以在第一个或最后一个副本块上使用类似Duff的设备(在OP问题的评论中提到))。
可能要从“外部”提供k。使用另一个外部模式来获取它很容易实现。
现在,要学会使用像DMS这样的引擎,部分原因是您正在处理已经非常复杂的C ++,部分原因是DMS的机制必须能够处理C ++抛出的所有异常情况。 [由于相同的原因,Clang同样会很难应用,但不提供模式驱动的转换机制。]
因此使用DMS just 一次执行一次 可能不是您的时间的好习惯。如果必须重复执行此操作,或者在大型代码库中可靠地执行更复杂的操作,那么就有意义。我的两分钱。
答案 1 :(得分:0)
Clang似乎是一个很好的工具,因为它有很多关于源到源转换的炒作。我查看是否有人进行了源到源的展开,并找到了一个基于Clang构建的Scout项目,可以实现您的需求:
https://fusionforge.zih.tu-dresden.de/scm/viewvc.php/trunk/Scout/?root=hicfd&sortby=log&pathrev=151
幻灯片:http://tau.dlr.de/fileadmin/documents/meetings/2009/pdf/TU_Dresden_ZIH.pdf
视频:http://www.irill.org/videos/euro-llvm-2013/krzikalla-hires.webm