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

            Bug ID: 127883
           Summary: x86-64: unnecessary zero-extension after byte
                    extraction
           Product: gcc
           Version: 16.2.1
            Status: UNCONFIRMED
          Keywords: missed-optimization
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: adamant.pwn at gmail dot com
  Target Milestone: ---
            Target: x86_64-pc-linux-gnu

Created attachment 65831
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65831&action=edit
GCC 16.2.1 version and configure options

Indexing std::array by a byte extracted from a 64-bit value emits an extra
instruction compared with a raw array:

#include <array>

extern const std::array<unsigned short, 256> table;
extern const unsigned short raw[256];

extern "C" unsigned short std_array(unsigned long long x) {
    return table[static_cast<unsigned char>(x >> 24)];
}
extern "C" unsigned short raw_array(unsigned long long x) {
    return raw[static_cast<unsigned char>(x >> 24)];
}

Compile with:
g++ -std=c++20 -O2 -S -masm=intel comparison.cpp

GCC's index extraction:

std_array:
    shr     rdi, 24
    movzx   edi, dil

raw_array:
    shr     edi, 24

Both compute the same index (bits 24..31, range 0..255). The 32-bit shift also
clears the upper bits and should suffice for both; Clang 23.1.1 generates it
for both.

Explicitly converting the raw-array index to std::size_t reproduces the extra
instruction. std::array::operator[] performs that conversion, exposing a missed
narrowing before zero-extension.

Reproduced with GCC 15.3.0 and GCC 16.2.1 20260810 on x86_64-pc-linux-gnu at
-O2/-O3, without architecture flags. Also reproduced with Compiler Explorer GCC
trunk (gsnapshot, tested 2026-10-14). No diagnostics. Compiler configuration
and preprocessed source are attached.

Reply via email to