microsoft / GSL

Guidelines Support Library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

size_bytes unnecessarily optimizes poorly

JosephBialekMsft opened this issue · comments

The span function size_bytes is currently implemented as follows:

    constexpr size_type size_bytes() const noexcept
    {
        Expects(size() < dynamic_extent / sizeof(element_type));
        return size() * sizeof(element_type);
    }

This check is attempting to ensure that the multiplication doesn't overflow. This check is not actually needed because it is not possible for "size" to become so large that the overflow occurs. The only way this could happen is if the span was somehow representing more than size_t bytes worth of data but there's no room in the virtual address space for this.

It leads to code optimizing poorly. In my current project I am calling size_bytes and it is actually a function call (I imagine because this code is compiled for size and size_bytes is a lot of code).

binary!gsl::span<unsigned char const ,-1>::size_bytes:
00000001`40434650 4883ec28        sub     rsp,28h
00000001`40434654 488b01          mov     rax,qword ptr [rcx]
00000001`40434657 4883f8ff        cmp     rax,0FFFFFFFFFFFFFFFFh
00000001`4043465b 7306            jae     binary!gsl::span<unsigned char const ,-1>::size_bytes+0x13 (00000001`40434663)
00000001`4043465d 4883c428        add     rsp,28h
00000001`40434661 c3              ret
00000001`40434662 cc              int     3
00000001`40434663 e864000000      call    binary!gsl::details::terminate (00000001`404346cc)

Notice since this is a span of bytes, there is a comparison to check if rax (the size) is bigger than or equal to 0xFFFFFFFF'FFFFFFFF. There is no way a span could be this big, and this check is resulting in a ton of code generation for what should just be loading the size field and returning it.

Hi @JosephBialekMsft
Thanks for noticing this, I will bring it up at the next maintainer's sync.

Dmitry