我想在源代码级自动解析用C编写的目标程序中的循环(仅供参考,我使用linux和gcc编译器)。 有关详细说明,请参阅以下简单源代码。
1: int main(){
2: int i = 0;
3: while(i<3){
4: printf("hi\n");
5: i++;
6: }
7: }
我想将上述源代码转换如下。
1: int main(){
2: int i = 0;
3: if (i<3){
4: printf("hi\n");
5: i++;
6: }
7: if (i<3){
8: printf("hi\n");
9: i++;
10: }
11: if (i<3){
12: printf("hi\n");
13: i++;
14: }
15:}
我知道CBMC会自动解除循环以进行软件模型检查,但我不确定CBMC是否将源代码转换为源代码以进行展开循环。 我需要获得一个程序源代码,其中所有循环都是unwinded。
我试图为此找到工具或解决方案,但我找不到。 任何建议或意见将不胜感激。 谢谢!
很抱歉让您感到困惑。我将解释我在“源代码级别循环展开”的最终目标的细节。 我解除循环的最终目标是测量执行从循环展开生成的语句的测试用例数。 请参阅以下示例。
1: void ex(int i){
2: int i = 0;
3: while(i<3){
4: printf("hi\n");
5: i++;
6: }
7: }
当我转换上面的源代码时,我希望获得以下源代码
1: void ex(int i){
2: if (i<3){
3: printf("hi\n");
4: i++;
5: }
6: if (i<3){
7: printf("hi\n");
8: i++;
9: }
10: if (i<3){
11: printf("hi\n");
12: i++;
13: }
14:}
从上面转换的源代码中,我将测量执行来自“loop unwinding”的每个语句的测试用例的数量。 例如,执行从原始源代码中的第4行和第5行转换的第#3,4行或第7,8行或第11,12行的测试用例的数量将与执行行的测试用例的测试用例的数量不同原始源代码中的#4,5。
仅供参考,如果有一种方法可以在没有循环展开的情况下实现我的最终目标,那么方式也很好! 谢谢!
答案 0 :(得分:1)
几乎总是,在确定某些代码是否适合展开代码时,gcc会比你做得更好。根据我的经验,你可以比gcc做得更好,这是非常罕见的 - 唯一合理的情况是当你有非常复杂的代码做“奇怪”的事情时,你的例子肯定不是这样。
您是否真的尝试过使用带优化的-S选项来查看编译器的功能?
当然,编译器可能有意义不优化这个特定的循环,因为printf()比所有的循环重得多 - 但这是一个稍微不同的事情。
答案 1 :(得分:0)
循环展开只是GCC完成的一次(多次)优化(至少在-O2
或-O3
),并且本身没有意义。 (只有通过其他优化才有帮助,比如不断的传播)。
你当然不能只想要一个源代码(想象很多宏可以扩展到for
循环,这些循环得到循环展开。)
我建议您扩展GCC编译器,例如使用MELT这是一种扩展GCC的高级域特定语言
(或者,如果你有很多时间,通过在C中痛苦地编写你的GCC插件)。
然后你会在一些循环展开(以及其他优化)传递之后添加一个传递来处理Gimple内部表示(你可以理解Gimple是一种“最小”的C语言,只有基本操作à{{1}和调用以及x = y + z;
)之类的简单测试。
但我仍然不明白你想对结果做些什么。如果要进一步分析它,请处理(可能是在MELT中编码的另一个传递)编译器内部的GCC内部表示。如果要将“展开的”代码提供给某些外部工具,请编写一个转换过程,将Gimple转换为某种适当的格式。
答案 2 :(得分:0)
你应该查看汇编程序,看看编译器在循环展开时实际上有多好。但是你也可以帮助你的编译器编程更好一点:
for (unsigned i = 0; i < 3; ++i) {
printf("hi\n");
}
使用无符号整数类型作为循环变量(size_t
通常是一个好主意)并将循环变量设置为local。然后使用类似-S -O3 -march=native
的编译器选项检查汇编器。
然后,只有这样,如果您对结果不满意,请查看P99。它有一组宏可以展开,不仅适用于循环。寻找类似P99_FOR
的内容。