Ho un codice che è più o meno così:
#include <bitset>
enum Flags { A = 1, B = 2, C = 3, D = 5,
E = 8, F = 13, G = 21, H,
I, J, K, L, M, N, O };
void apply_known_mask(std::bitset<64> &bits) {
const Flags important_bits[] = { B, D, E, H, K, M, L, O };
std::remove_reference<decltype(bits)>::type mask{};
for (const auto& bit : important_bits) {
mask.set(bit);
}
bits &= mask;
}
Clang> = 3.6 fa la cosa intelligente e la compila in una singola and
istruzione (che poi viene inline ovunque):
apply_known_mask(std::bitset<64ul>&): # @apply_known_mask(std::bitset<64ul>&)
and qword ptr [rdi], 775946532
ret
Ma ogni versione di GCC che ho provato compila questo in un enorme pasticcio che include la gestione degli errori che dovrebbe essere staticamente DCE. In un altro codice, posizionerà anche l' important_bits
equivalente come dati in linea con il codice!
.LC0:
.string "bitset::set"
.LC1:
.string "%s: __position (which is %zu) >= _Nb (which is %zu)"
apply_known_mask(std::bitset<64ul>&):
sub rsp, 40
xor esi, esi
mov ecx, 2
movabs rax, 21474836482
mov QWORD PTR [rsp], rax
mov r8d, 1
movabs rax, 94489280520
mov QWORD PTR [rsp+8], rax
movabs rax, 115964117017
mov QWORD PTR [rsp+16], rax
movabs rax, 124554051610
mov QWORD PTR [rsp+24], rax
mov rax, rsp
jmp .L2
.L3:
mov edx, DWORD PTR [rax]
mov rcx, rdx
cmp edx, 63
ja .L7
.L2:
mov rdx, r8
add rax, 4
sal rdx, cl
lea rcx, [rsp+32]
or rsi, rdx
cmp rax, rcx
jne .L3
and QWORD PTR [rdi], rsi
add rsp, 40
ret
.L7:
mov ecx, 64
mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:.LC1
xor eax, eax
call std::__throw_out_of_range_fmt(char const*, ...)
Come devo scrivere questo codice in modo che entrambi i compilatori possano fare la cosa giusta? In caso contrario, come dovrei scriverlo in modo che rimanga chiaro, veloce e gestibile?
(1ULL << B) | ... | (1ULL << O)
(1ULL << Constant)
| per riga e allineare i nomi delle costanti sulle diverse righe, che sarebbe più facile per gli occhi.
int
risultato dell'operazione di bit PU ESSERE int
O può long long
dipendere dal valore e formalmente enum
non è un equivalente a una int
costante. clang chiama "come se", gcc rimane pedante
B | D | E | ... | O
?