https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87090

            Bug ID: 87090
           Summary: Constexpr variables in functions are not optimized
                    correctly
           Product: gcc
           Version: 8.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: jeanmichael.celerier at gmail dot com
  Target Milestone: ---

Consider the following code :

    #include <string_view>
    #include <array>

    struct Table 
    {
      long long tab[128];
      constexpr Table() 
        : tab {} 
      {
        tab['0'] = 0;
        tab['1'] = 1;
        tab['2'] = 2;
        tab['3'] = 3;
        tab['4'] = 4;
        tab['5'] = 5;
        tab['6'] = 6;
        tab['7'] = 7;
        tab['8'] = 8;
        tab['9'] = 9;
        tab['a'] = 10;
        tab['A'] = 10;
        tab['b'] = 11;
        tab['B'] = 11;
        tab['c'] = 12;
        tab['C'] = 12;
        tab['d'] = 13;
        tab['D'] = 13;
        tab['e'] = 14;
        tab['E'] = 14;
        tab['f'] = 15;
        tab['F'] = 15;
      }

      constexpr auto operator[](const std::size_t idx) const { return tab[idx];
} 
    } constexpr t;

    constexpr auto conv(std::size_t number) 
    {
      return t[number];
    }

    std::array<long long, 4> res;

    void convert(std::string_view hex)
    {
        res[0] = (conv(hex[1]));
        res[1] = (conv(hex[3]));
        res[2] = (conv(hex[5]));
        res[3] = (conv(hex[7]));
    }

When benchmarking it (calling the `convert("#00ABCDEF")` function a few million
times from another translation unit), I get the following numbers consistently
: 

    g++-8.2.0 : 8-9 nanoseconds per call
    clang++-6.0.1 : 8-10 nanoseconds per call

Now, if I want to put the table inside the conv function to keep it in a small
scope, such as this : 

    constexpr auto conv(std::size_t number) 
    {
      struct Table 
      {
        long long tab[128];
        constexpr Table() 
          : tab {} 
        {
          tab['0'] = 0;
          tab['1'] = 1;
          tab['2'] = 2;
          tab['3'] = 3;
          tab['4'] = 4;
          tab['5'] = 5;
          tab['6'] = 6;
          tab['7'] = 7;
          tab['8'] = 8;
          tab['9'] = 9;
          tab['a'] = 10;
          tab['A'] = 10;
          tab['b'] = 11;
          tab['B'] = 11;
          tab['c'] = 12;
          tab['C'] = 12;
          tab['d'] = 13;
          tab['D'] = 13;
          tab['e'] = 14;
          tab['E'] = 14;
          tab['f'] = 15;
          tab['F'] = 15;
        }

        constexpr auto operator[](const std::size_t idx) const { return
tab[idx]; } 
      } constexpr t;

      return t[number];
    }

I get the following numbers : 

    clang++-6.0.1 : 8-10 nanoseconds per call (no changes)
    g++-8.2.0 : 120-150 nanoseconds per call, more than ten times slower !

I tested for both compiles at -O2 and -O3 without observable changes.

If I make the "conv" function itself non-constexpr, and mark the table as
static constexpr, I get my performance back - I guess that even while constexpr
the table must be initialized each time ?

Reply via email to