0

I want to unwind loops in the target program written in C at the source code level automatically (FYI, I use linux and gcc compiler). For the detailed description, let's see the following simple source code.

1: int main(){
2:   int i = 0;
3:   while(i<3){
4:     printf("hi\n");
5:     i++;
6:   }
7: }

I want to convert the above source code as follows.

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:}

I know CBMC does unwinding loops automatically for software model checking but I am not sure the CBMC converts source code to source code for unwinding loops. I need to get a program source code where all the loops are unwinded.

I have tried to find tools or solutions for that, but I couldn't find that. Any suggestions or comments would be appreciated. Thanks!


Sorry for confusing you. I will explain details of my final goal of "loop unwinding at source code level". My final goal of unwinding loops is measuring # of test cases executing statements which are generated from loop unwinding. Refer to the following a example.

1: void ex(int i){
2:   int i = 0;
3:   while(i<3){
4:     printf("hi\n");
5:     i++;
6:   }
7: }

When I convert the above source code, I want to get following source code

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:}

And from the above converted source code, I will measure # of test cases executing each statement that comes from "loop unwinding". For example, the numbers of test cases executing line #3,4 or line #7,8 or line #11,12 that were converted from line #4 and 5 in the original source code would be different from that of test cases executing line#4,5 in the original source code.

FYI, if there is a way that can achieve my final goal without loop unwinding, the way is also good! Thanks!

Charles
  • 50,943
  • 13
  • 104
  • 142
freddy
  • 463
  • 1
  • 8
  • 20
  • The compiler is already doing that .... And for your example, it probably will get just three instances of `printf("hi\n");` without any remaining test or increment of `i` – Basile Starynkevitch Dec 31 '12 at 08:06
  • Why exactly do you ask? What do you want to do with the output?? Why do you need it to be some "source code"? Are you feeding it to another tool? Which one? – Basile Starynkevitch Dec 31 '12 at 08:14
  • Thanks for your reply. By the way, is there a way to get the source code where all loops are unwinded? This was my question :) – freddy Dec 31 '12 at 08:16
  • The coverage of converted source code will be measured by using Gcov for some purpose. – freddy Dec 31 '12 at 08:18
  • I don't understand your question. It seems that you wrongly believe that a compiler is transforming *source code*; it is not. It is parsing source code into some internal representations, and transforming internal representations into other ones. – Basile Starynkevitch Dec 31 '12 at 08:19
  • Then just try to use `gcov` with an optimizing GCC compilation. – Basile Starynkevitch Dec 31 '12 at 08:21
  • So, are you trying to understand "is this path covered in all iterations of the loop" or some such? Sounds like a task for valgrind or some such, rather than gcov - and I don't think unrolling the loop would be representative - never mind the fact that if the loop is very long, the unrolled code may not be feasible [e.g several nested loops of several thousand each] – Mats Petersson Dec 31 '12 at 08:40

3 Answers3

1

Almost always, gcc will do a better job than you at determining if some code is suitable for unrolling the code. In my experience, it is EXTREMELY rare that you can do a better job than gcc - the only reasonable cases is when you have very complicated code that does "strange" things, and that's certainly not the case in your example.

Have you actually tried using the -S option with optimization to see what the compiler does?

Of course, the compiler may have the sense to NOT optimize this particular loop, since the printf() is MUCH heavier than all of the loop together - but that's a slightly different matter.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • And the option `-fdump-tree-all` (and other similar options) produce hundreds of dump files showing a textual form of internal GCC representations at various stages of the compilation. – Basile Starynkevitch Dec 31 '12 at 08:22
0

Loop unrolling is just one (in many) optimizations done by GCC (at least at -O2 or -O3), and does not have sense by itself. (It is helpful only thru other optimizations, like constant propagations).

And you certainly cannot just want a source code (imagine that many macros may be expanded to for loops which get loop-unrolled).

I would suggest you to extend the GCC Compiler, for instance with MELT which is a high-level domain specific language to extend GCC

(or, if you have a lot of time, by painfully coding your GCC plugin in C).

Then you would add a pass after some loop-unrolling (and other optimizing) passes which would process Gimple internal representation (you could understand Gimple as a "minimal" C like language, with only elementary operations à la x = y + z; and calls and simple tests like if (x > y) goto l;).

But I still don't understand what you want to do with the result. If you want to further analyze it, handle (perhaps with another pass coded in MELT) the GCC internal representations inside the compiler. If you want to feed that "unrolled" code to some external tool, write a converting pass which would transform the Gimple to some appropriate format.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
0

You should look into the assembler to see how good compilers actually are in loop unrolling. But you could also help your compiler in programming a bit nicer:

for (unsigned i = 0; i < 3; ++i) {
  printf("hi\n");
}

that is using unsigned integer types as loop variables (size_t is often a good idea) and by having the loop variable local. Then inspect the assembler with something like -S -O3 -march=native as compiler options.

Then, and only then, if you are not satisfied with the result, have a look into P99. It has a set of macros to do unrolling, not only for loops. Look for something like P99_FOR.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177