1) if DEBUG_IF macro will be nested and top level if is false, then debug system will not see nested if or other nested variables. This means during recompilation debug system will not be able to generate GlobalConstants_xyz define in "handmade_config.h" file. Before this was not a problem, because all variables were manually listed. Now it is a problem. For example:
1 2 3 4 5 6 7 8 | DEBUG_IF(Something_UseFoo) { DEBUG_IF(SomethingElse_UseBar) { DEBUG_VARIABLE(r32, Renderer_Camera, DebugDistance); DistanceAboveTarget += DebugDistance; } } |
If "Something_UseFoo" is false then debug system won't be able to generate these two lines:
1 2 | #define GlobalConstants_SomethingElse_UseBar 0 #define GlobalConstants_Renderer_Camera_DebugDistance 25.0f |
This means code won't compile after "handmade_config.h" file is regenerated.
2) local "static" variables (local_persist) are NOT thread-safe in MSVC 2013. In C++ standard local static variables are thread safe only starting with C++11 compiler. This means if compiler supports C++11 it is required to generate thread-safe code for local static variables. Otherwise it can do whatever it wants. MSVC 2013 (and lower) are not C++11 compatible compiler, so it generates non thread-safe code. MSVC 2015 is C++11 compatible compiler - it generates thread-safe code. GCC recent versions always generate thread safe code.
Here's an example:
1 2 3 4 5 | int f(int x) { static int a = x; return a; } |
MSVC 2013 generates following assembly (x64):
1 2 3 4 5 6 7 8 9 10 11 12 | ?f@@YAHH@Z PROC ; f, COMDAT mov eax, ecx mov ecx, DWORD PTR ?$S1@?1??f@@YAHH@Z@4IA test cl, 1 jne SHORT $LN4@f or ecx, 1 mov DWORD PTR ?a@?1??f@@YAHH@Z@4HA, eax mov DWORD PTR ?$S1@?1??f@@YAHH@Z@4IA, ecx ret 0 $LN4@f: mov eax, DWORD PTR ?a@?1??f@@YAHH@Z@4HA ret 0 |
MSVC 2015 generates following assembly (x64):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ?f@@YAHH@Z PROC ; f, COMDAT push rbx sub rsp, 32 ; 00000020H mov edx, DWORD PTR _tls_index mov ebx, ecx mov rax, QWORD PTR gs:88 mov ecx, OFFSET FLAT:_Init_thread_epoch mov rax, QWORD PTR [rax+rdx*8] mov edx, DWORD PTR [rcx+rax] cmp DWORD PTR ?$TSS0@?1??f@@YAHH@Z@4HA, edx jle SHORT $LN4@f lea rcx, OFFSET FLAT:?$TSS0@?1??f@@YAHH@Z@4HA call _Init_thread_header cmp DWORD PTR ?$TSS0@?1??f@@YAHH@Z@4HA, -1 jne SHORT $LN4@f lea rcx, OFFSET FLAT:?$TSS0@?1??f@@YAHH@Z@4HA mov DWORD PTR ?a@?1??f@@YAHH@Z@4HA, ebx call _Init_thread_footer $LN4@f: mov eax, DWORD PTR ?a@?1??f@@YAHH@Z@4HA add rsp, 32 ; 00000020H pop rbx ret 0 |
gcc 5.2.0 generates following assembly (x64):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | _Z1fi: pushq %rbx subq $32, %rsp cmpb $0, _ZGVZ1fiE1a(%rip) movl %ecx, %ebx je .L7 .L5: movl _ZZ1fiE1a(%rip), %eax addq $32, %rsp popq %rbx ret .L7: leaq _ZGVZ1fiE1a(%rip), %rcx call __cxa_guard_acquire testl %eax, %eax je .L5 leaq _ZGVZ1fiE1a(%rip), %rcx movl %ebx, _ZZ1fiE1a(%rip) call __cxa_guard_release movl %ebx, %eax addq $32, %rsp popq %rbx ret |
As you can see both MSVC 2015 and gcc use some internal C runtime functions to guarantee that local static variable is initialized only once. MSVC 2013 doesn't.
You can actually make statics non thread-safe if you want - use "-fno-threadsafe-statics" for gcc and "/Zc:threadSafeInit" for MSVC 2015.
clang generates either gcc or msvc style of code - depeneding on what runtime you are targeting.
So on MSVC 2013 this can potentially lead to duplicate allocation of variables in debug system.