0

In this question, I meet the situation that gcc myfile.c -S produce the assembly code that is better than gcc myfile.c -O0 but worse than gcc myfile.c -O1.

At -O0, both loops are generated. At -O1, both loops are optimized out. (Thanks @Raymond Chen for reminder. cited from his comments) (using the -S just optimize one loop out)

I search the Internet and only find this:

-S (cited from Overall options)

Stop after the stage of compilation proper; do not assemble. The output is in the form of an assembler code file for each non-assembler input file specified.

By default, the assembler file name for a source file is made by replacing the suffix ‘.c’, ‘.i’, etc., with ‘.s’.

Input files that don't require compilation are ignored.

So my question is:

  • what is exactly the optimization level of -S option when it compile file? (-O0.5?)

  • why not just using the -O0 or -O1... (or it is a bug?)

Edit: you can use this site to help you reproduce the problem. Code is in the question I mentioned. ( If you just use -S compiler option(or no compiler option), you can get one loop elision. )

step 1:

Open this site and copy the following code in Code Eidtor.

 #include <stdio.h>
 int main (int argc, char *argv[]) {

   unsigned int j = 10;

   for (; j > -1; --j) {    
      printf("%u", j);
   }
 }

step 2:

Choose g++ 4.8 as compiler. Compiler option is empty.(or -S)

step 3:

You get the first situation. Now, change the j > -1 to j >= -1 and you can see the second.

Community
  • 1
  • 1
Tony
  • 5,972
  • 2
  • 39
  • 58
  • 2
    -S does not control optimization, it's controlled with the -O switch, so what you're seeing should not happen. Nor can I reproduce this. Please post some code and the exact commands you use to reproduce this behavior. – nos Aug 04 '14 at 12:07
  • @nos In this site(http://gcc.godbolt.org/), you can try my code in that question. If I paste those code here, wouldn't be duplicate? – Tony Aug 04 '14 at 12:18
  • @Tony: Which exact version of GCC is this? – Aaron Digulla Aug 04 '14 at 12:57
  • On above site which GCC version did you choose (site defaults to clang!)? – dbrank0 Aug 04 '14 at 13:34
  • @Tony It's generally much much easier when you post the exact code and the exact steps to reproduce a problem, instead of sending us off to other questions and web sites. I can't reproduce your results, and I don't know what you have done to produce those results. – nos Aug 04 '14 at 14:08
  • @AaronDigulla I use GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2. And at that site, I choose g++ 4.8. – Tony Aug 04 '14 at 14:10
  • I get same code generated for -O0, -S and no flags. But code generated for j>-1 and j>= -1 is different. BTW #1: What is this code supposed to do? -1 is converted to 0xffffffff... and loop never executes. BTW #2: I think you should compare optimized code. – dbrank0 Aug 04 '14 at 14:55
  • @dbrank0 I use the code to test whether compare a signed int and unsigned int will lead conversion and get something I can't understand. So I want to see reasons in assembly code and finally I get there. :( – Tony Aug 04 '14 at 15:05
  • In this case you should just use "for (; j > 1; --j)" in loop, build with optimization and you will be able to notice that "unsigned comparison" conditional branches (jbe, ja) are used. So in effect both numbers are treated as unsigned. With your -1 value GCC always does some pre-processing and it looks even with no optimization it notices that with j > -1 (in effect "some unsigned int" > "max unsigned int") can never be true and removes whole statement. – dbrank0 Aug 04 '14 at 15:41

2 Answers2

1

-S doesn't optimize. -O0, on the other hand, disables all and any optimizations, even the default ones.

So the effect that you see is that you're "enabling" the default optimizations if you use just -S.

Use -S with various -O options to see the effect on the assembler code.

EDIT I've been using GCC since about 2.6 (in 1994). I'm pretty sure I remember that in some versions, the compiler would do default optimizations that you could disable with -O0 to debug the compiler (i.e. gcc ... crashes, gcc -O0 ... doesn't crash -> congrats, you found a bug).

But that doesn't seem to be the case here. I get the same assembler output for -S, -O0 and not giving either. So it seems that the simple optimizations (like if(0){} to comment out a code block) are always applied, no matter which optimization level is selected.

Therefore, I'd say is that original statement above:

At -O0, both loops are generated. At -O1, both loops are optimized out. (Thanks @Raymond Chen for reminder. cited from his comments) (using the -S just optimize one loop out)

is not correct to begin with (at least for GCC 4.8.2). The only other alternative is that the GCC version used by the OP (4.8) has a bug when it comes to enabling/disabling optimizer options.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • 2
    But in this site (https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html), it say `-O0` 'Reduce compilation time and make debugging produce the expected results. This is **the default**. ' – Tony Aug 04 '14 at 12:29
  • 1
    @Tony: No, it is not, although the documentation says so. A minimum set of optimizations is always performed, unless you explicitly tell the compiler not to do this with `-O0`. – Damon Aug 04 '14 at 12:32
  • Damon: Are you sure? In this case a bug report should be created for the GCC documentation. – dbrank0 Aug 04 '14 at 12:49
  • Just tried bulding ~30000 LOC program with -O0 and without any -O and the disassembled executable shows no differences. – dbrank0 Aug 04 '14 at 12:55
  • Which version of GCC are we talking about here? – Aaron Digulla Aug 04 '14 at 12:58
  • I did above test with gcc 4.8.2 (Ubuntu 4.8.2-19ubuntu1) - default gcc on 64-bit ubuntu 14.04. – dbrank0 Aug 04 '14 at 13:04
  • @dbrank0: Maybe my knowledge is outdated. But looking at the comments of the original questions, it seems several people had problems to reproduce the results. Can you get the results in the original question with your version of GCC? – Aaron Digulla Aug 04 '14 at 13:13
  • Added both versions of original code to two functions in a .c file. Compiled with 1) -O0, 2) without any flags, 3) with -S -o out.S (and this I later assembled with gcc out.S -o out.assembled). Disassembled all three executables and they are the same. (again default ubuntu gcc 4.8.2) – dbrank0 Aug 04 '14 at 13:33
  • What's the point of running the assembler and then disassembling again when you already have the assembler sources? – Aaron Digulla Aug 04 '14 at 14:57
  • disassembler's output looks different than what gcc produces with -S. It's easier to do diff when all executables are disassembled. – dbrank0 Aug 04 '14 at 15:05
1

With your last edit, it's now somewhat clear what you're actually doing, so:

For the 1. case, j > -1

This can never happen. j is an unsigned int, and -1 converted to an unsigned value will correspond to a value with all bits being set. That's the same as UINT_MAX, and j can never be greater than that. So gcc eliminates the loop, since its condition will always be false

For the 2. case, j >= -1:

This can happen. j can surely become (unsigned int)-1, or UINT_MAX as mentioned above. The loop is not eliminated.

what is exactly the optimization level of -S option when it compile file? (-O0.5?)

The optimization level is controlled with the -O flag. The -S does not impact optimization. The default optimization if no -O flag is given is -O0 (no optimization)

nos
  • 223,662
  • 58
  • 417
  • 506