Isn't the correct way to write this loop actually:
void toupper_cmov(char* buf, size_t size) {
for (size_t i = 0; i < size; i++) {
char c = buf[i];
buf[i] = c - 32 * (c >= 'a' && c <= 'z');
}
}
Because that persuades gcc and clang to transform the conditional branch into a conditional move which avoids the branch mispredict penalty and removes the need for a lookup table.See https://godbolt.org/z/xHYKft
Disclaimer: I haven't actually run this function. That would be too much like work.