1

Given the following C++ code:

#include <stdio.h>

static constexpr int x = 1;

void testfn() {
    if (x == 2)
        printf("This is test.\n");
}

int main() {
    for (int a = 0; a < 10; a++)
        testfn();
    return 0;
}

Visual Studio 2019 produces the following Debug build assembly (viewed using Approach 1 of accepted answer at: How to view the assembly behind the code using Visual C++?)

int main() {
00EC1870  push        ebp  
00EC1871  mov         ebp,esp  
00EC1873  sub         esp,0CCh  
00EC1879  push        ebx  
00EC187A  push        esi  
00EC187B  push        edi  
00EC187C  lea         edi,[ebp-0CCh]  
00EC1882  mov         ecx,33h  
00EC1887  mov         eax,0CCCCCCCCh  
00EC188C  rep stos    dword ptr es:[edi]  
00EC188E  mov         ecx,offset _6D4A0457_how_compiler_treats_staticconstexpr@cpp (0ECC003h)  
00EC1893  call        @__CheckForDebuggerJustMyCode@4 (0EC120Dh)  
    for (int a = 0; a < 10; a++)
00EC1898  mov         dword ptr [ebp-8],0  
00EC189F  jmp         main+3Ah (0EC18AAh)  
00EC18A1  mov         eax,dword ptr [ebp-8]  
00EC18A4  add         eax,1  
00EC18A7  mov         dword ptr [ebp-8],eax  
00EC18AA  cmp         dword ptr [ebp-8],0Ah  
00EC18AE  jge         main+47h (0EC18B7h)  
        testfn();
00EC18B0  call        testfn (0EC135Ch)  
00EC18B5  jmp         main+31h (0EC18A1h)  
    return 0;
00EC18B7  xor         eax,eax  
}

As can be seen in the assembly, possibly because this is a Debug build, there is pointless references to the for loop and testfn in main. I would have hoped that they should not find any mention in the assembly code at all given that the printf in testfn will never be hit since static constexpr int x=1.

I have 2 questions:

(1)Perhaps in the Release build, the for loop is optimized away. How can I check this? Viewing the release build assembly code does not work for me even on using the Approach 2 specified at at: How to view the assembly behind the code using Visual C++?. The file with the assembly code is not produced at all.

(2)In using static constexpr int/double/char as opposed to #define's, under what circumstances is one guaranteed that the former does not involve any unnecessary overhead (runtime computations/evaluations)? #define's, though much maligned, seem to offer much greater guarantee than static constexpr's in this regard.

Tryer
  • 3,580
  • 1
  • 26
  • 49
  • 1
    [The compiler explorer](https://godbolt.org) is very useful to check such things. You can add two compilers (both being the VC++ compiler) and have different optimization flags to immediately see differences in the generated code. – Some programmer dude Oct 01 '19 at 05:00
  • 2
    [This specific example on Godbolt](https://godbolt.org/z/I_AczI). Note that `main` has been completely optimized away in the release build. – user703016 Oct 01 '19 at 05:04
  • @user703016 Thanks. Is there a way to view the release version assembly output in Visual Studio IDE? – Tryer Oct 01 '19 at 09:04

1 Answers1

4

The issue here is that you are compiling the code using a debug build. If you want sanity in the asm, compile as release instead. The problem is that a debugger is used to help confirm the logic of the underlying code. The logic in your underlying code is that it should call testfn() 10 times. As a result, you should be able to place a breakpoint on that method, and hit it at the correct point in the execution. In a release build, that breakpoint would never be hit (because it would have been optimised away).

In your case however, it's entirely incorrect to say that the constexpr is being ignored. You may notice that there are no calls to printf() in the generated asm, so the compiler has correctly identified that if (x == 2) can never be true, and has removed it. However, if the compiler removed the call to testfn() completely, your breakpoint would never be hit, and the debugger would basically be useless.

Don't look at the output of a debug build and imagine it tells you anything useful about the code or compiler. You should expect the code to be deliberately de-optimised.

robthebloke
  • 9,331
  • 9
  • 12
  • This is correct, one of the most important points of debug code is that you can step through it with a debugger and see what your lines of code do. If you try to do that with a release build, where lots of lines have been optimized out, then you will find the debugger jumping around to the point that you will have problems recognizing your own program - and, as mentioned, you will be unable to place breakpoints half the places you want to. – Frodyne Oct 01 '19 at 06:43
  • I agree with the need for debug version to be faithful to the C++ code. Is there a way to view the actual release version assembly in Visual Studio IDE? Also, are you aware of static constexpr int/double/char (inbuilt types) guarantees that they will be treated like #define's in release builds? – Tryer Oct 01 '19 at 09:07
  • Yeah, just enable the asm output in the project settings. It usually dumps the files out somewhere odd (build folder sometimes? I Don't have a windows PC to hand at the moment). godbolt is usually a better bet imho: https://godbolt.org/z/gCIRAR (take note of the compiler flags). You can see that testfun() just returns, and main() just xors a register together to generate 'return 0'. – robthebloke Oct 02 '19 at 00:08