自动展开和输出C/C ++代码 [英] Automatically unrolling and outputting for C/C++ code

查看:124
本文介绍了自动展开和输出C/C ++代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一个实验,第一步是(从C/C ++)展开一个循环十次(例如:10、50等),然后输出C/C ++展开的代码.有什么我可以用来自动进行此类展开的工具吗?

I'm doing an experiment and the first step is to unroll a loop (from C/C++) a dozen of times (ex: 10, 50, etc) and output the C/C++ unrolled code. Is there any tool that I can use to automatize such unrolling?

换句话说,我需要的是:

In other words, what I need is:

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

推荐答案

我们的源到源转换引擎, DMS软件再造工具包, 其 C ++ 17前端可以用于做到这一点.

Our source-to-source transformation engine, the DMS Software Reengineering Toolkit, with its C++17 front end can be used to do this.

DMS可以接受明确的源到源转换规则.

个人规则写为

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

下面,我提供了一个非常接近商标的(未嵌套)集.这些都是直接受经典的用于展开循环的编译器优化的启发.

Below I provide an (untested) set that are pretty close to the mark. These are directly inspired by the classic compiler optimization for unrolling a loop.

您在"..."内看到的...表示(C ++语法)...";这些是域文本元引号,而不是C ++字符串引号. "..."内的\ foo表示元变量foo,它表示C ++代码的一块(树). \ bar(... \,...)的意思是在...上调用了元函数栏".请注意,元逗号"的拼写为\,而元括号()则用于将元函数与域("C ++")语法区分开. 有关此类规则的语法的更多详细信息,请参见链接.

The ... inside "..." that you see means "(C++ syntax for) ..."; these are " here are domain text metaquotes, not C++ string quotes. \foo inside "..." means metavariable foo, which represents a chunk (tree) of C++ code. \bar(...\,...) means "metafunction bar invoked on ..." Note the "metacommas" spelled \, and metaparentheses ( ) used to distinguish metafunctions from domain ("C++") syntax. See the link for more details on the syntax of such rules.

未引用的模式UNROLL和ReplaceIbyEXP定义了元函数",可以将其视为应用更多转换的意图.

The unquoted patterns UNROLL and ReplaceIbyEXP define "metafunctions", which can be thought of as intentions to apply more tranformations.

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

Here UNROLL captures our notion that we want to repeat a block of code n times. There are two (effectively recursive) rules to implement this notion, one for the base case of "repeat zero times" producing an empty statement list, and the other generating the code block followed by repeating n-1 times. ReplaceIbyEXP then adjusts the index i used in the copied code block.

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) }"

此代码有很多问题要解决:

This code has a variety of hiccups to address:

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

  • It doesn't express the implementation of ReplaceIbyEXP; at present, that needs to be realized by calling DMS's procedural ("PARLANSE") part ("external") to do a tree walk and replace each instance of the matching identifier with the provided subexpression. In the procedural part these are already trees and simple "AST:EqualNode" and "AST:ReplaceSubtree" can be used to realize it. This is probably another 20 lines of PARLANSE code.

它不能处理循环边界不是k的倍数的情况.这意味着需要有UNROLL_FOR_k的变体,其中一个变量的循环绑定是一个倍数(这是这里提供的那个),而它不是倍数的情况.然后,需要生成k个副本的展开循环,然后生成限制代码的k个副本的限制的清除代码. (或者,可以在第一个或最后一个副本上使用类似Duff的设备(在对OP的问题的评论中提到)的设备.)

It doesn't handle the case where the loop bound is not a multiple of k. That means there needs to be variants of UNROLL_FOR_k, one where the loop bound is a multiple (that's the one provided here) and the case where it isn't a multiple. Then one needs to generate an unrolled loop of k copies, followed by cleanup code of limit modulo k copies of the code. (Alternatively, one can use something like Duff's device [mentioned in a comment on OP's question] on the first or last block of copies).

可能要从外部"提供k.可以使用另一个外部模式来轻松实现这一点.

One might want to supply k from the "outside". That is easily implemented using another external pattern to fetch it.

现在,要学会使用像DMS这样的引擎,部分原因是您正在处理已经非常复杂的C ++,部分原因是DMS的机制必须能够处理C ++抛出的所有异常情况. [出于相同的原因,Clang同样会很难应用,但不提供模式驱动的转换机制.]

Now, learning to use an engine like DMS is rather involved, partly you are dealing with C++ which is already extremely complicated, and partly because DMS's machinery has to be able to handle all the peccadillos that C++ throws up. [Clang will be equally hard to apply for the same reasons, but doesn't provide the pattern-driven transformation machinery].

因此使用DMS just 一次执行一次 可能不是您的时间的好习惯.如果您必须重复执行此操作,或者在大型代码库上可靠地执行更复杂的操作,那么就有意义了.我的两分钱.

So using DMS just to do this once is probably not a good use of your time. If you have to automate this repeatedly, or do something much more complex reliably on a big code base, then it makes sense. My two cents.

这篇关于自动展开和输出C/C ++代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆