msvc zero-initialization

Here are two code excerpts, both compiled with x86 msvc v19.14

(1) https://godbolt.org/z/xqad3W [uses memset]
(2) https://godbolt.org/z/31Esb4 [uses {}]

(1)
1
2
3
4
5
6
7
8
9
10
11
#include <cstring>

char foo() {
    char* filename = new char[32];
    ::memset(filename, 0, 32);

    char ch = filename[15];
    delete[] filename;
    
    return ch;
}


(2)
1
2
3
4
5
6
7
8
9
10
#include <cstring>

char foo() {
    char* filename = new char[32] {};

    char ch = filename[15];
    delete[] filename;

    return ch;
}


What's interesting here is that the code with C-style memset actually produces less assembly instructions than the code with C++-style {} to zero-init the array. Even with /O3 optimization. Now, I know that less instructions doesn't necessarily mean it's more optimal, and of course I am aware that this is most likely insignificant, but anyone have a guess as to why the it's so different? The code that uses {} for initialization has more mov instructions and a jmp. Do these two pieces of code actually have different behavior that I'm missing? Just figure I'd ask; I'm not really expecting anyone to know (unless you're an MSVC dev, lol).

clang compiles the logic into a simple xor/ret (zero-out and return)!
gcc is less optimal, but both code excerpts compile to the same assembly.
It seems msvc is the odd man out here.
Last edited on
Look at the assembly produced when compiling for MSVC x64. Less instructions for both code snippets.

Still more instructions for the uniform initialization version compared to the memset version.

It seems msvc is the odd man out here.

"Forget it, Jake, it's Microsoft."
Is there even an /O3 for this compiler?
I mean, crap like this is hardly "optimized":

1
2
        mov     DWORD PTR $T2[ebp], eax
        mov     eax, DWORD PTR $T2[ebp]

Using /O2 avoids the memset call entirely for both versions.
Last edited on
I don't see an /O3 option for MSVC. It might functionally be a different option.

https://docs.microsoft.com/en-us/cpp/build/reference/o-options-optimize-code?view=msvc-160
Huh you're right, Microsoft docs don't actually say anything about /O3, I must've just assumed that was a thing. But /O2 still produces more code with the uniform initialization version (x86 and x64), still disappointing.

<edit: removed buggy code from this post>
Last edited on
Using x64 msvc v19.28 with /O2, the relevant assembly is below.
The only difference is the extra test (bitwise logical 'and', ignoring result)
and the conditional jump instruction (jump if result was zero).
It's like the uniform init is doing an automatic test for a failed allocation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// char* filename = new char[32] {};
        mov     ecx, 32
        call    void * operator new[](unsigned __int64)
        test    rax, rax
        je      SHORT $LN3@foo
        xorps   xmm0, xmm0
        mov     rcx, rax
        movups  XMMWORD PTR [rax], xmm0
        movups  XMMWORD PTR [rax+16], xmm0

// char* filename = new char[32];
// ::memset(filename, 0, 32);
        mov     ecx, 32
        call    void * operator new[](unsigned __int64)
        xorps   xmm0, xmm0
        mov     rcx, rax
        movups  XMMWORD PTR [rax], xmm0
        movups  XMMWORD PTR [rax+16], xmm0

Last edited on
Topic archived. No new replies allowed.