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.