<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - Bad code generated for search in constexpr arrays"
   href="https://bugs.llvm.org/show_bug.cgi?id=39254">39254</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Bad code generated for search in constexpr arrays
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>clang
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Keywords</th>
          <td>code-quality
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>C++
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedclangbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>antoshkka@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>dgregor@apple.com, llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>The following code:

constexpr const char* find(const char* begin, const char* end, char value) {
    for (; begin != end; ++begin)
      if (*begin == value) return begin;
    return begin;
}

unsigned find_first_to_escape(const char* s, unsigned size) {
  for (unsigned i = 0; i < size; ++i) {
    const char c = s[i];
    if (c == '\\') {
      //static
       constexpr char allowed_2char_escapes[] = {
        '\"', '/', '\\', 'b', 'f' , 'n', 'r', 't'
      };

      ++i;
      const char* begin = allowed_2char_escapes;
      const char* end = begin + sizeof(allowed_2char_escapes);
      if (find(begin, end, s[i]) == end) return i - 1;

      continue;
    }

    if (c <= 0x1F) return i;
  }

  return -1;
}


When compiled with `-std=c++17 -O3` produces assembly with multiple suboptimal
places:
1) It writes the content of the `allowed_2char_escapes` to memory `mov qword
ptr [rsp - 8], r10`. Marking `allowed_2char_escapes` with `static constexpr`
fixes that and removes unnecessary memory write.
2) Clumsy jump table generated. It consumes many bytes and does not seem to be
optimal. For example the code that compares a single char consumes more
assembly instructions than all the char comparisons on GCC. Clang's jump table
size consumes additional ~552 bytes, while GCC does not have it at all.
3) More registers used than with GCC. This forces clang to unnecessarily
push/pop data on stack.

Assembly comparison for last stable versions: <a href="https://godbolt.org/z/5uJOiD">https://godbolt.org/z/5uJOiD</a>
Assembly comparison for trunks: <a href="https://godbolt.org/z/GxspEi">https://godbolt.org/z/GxspEi</a></pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>