다음과 같은 코드가 있습니다.
#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 은 현명한 작업을 수행하고이를 단일 and
명령어로 컴파일합니다 (그런 다음 다른 모든 곳에서 인라인 됨).
apply_known_mask(std::bitset<64ul>&): # @apply_known_mask(std::bitset<64ul>&)
and qword ptr [rdi], 775946532
ret
그러나 내가 시도한 GCC의 모든 버전은 이것을 정적으로 DCE해야하는 오류 처리를 포함하는 엄청난 혼란으로 컴파일합니다. 다른 코드에서는 코드 important_bits
와 함께 동등한 데이터를 데이터로 배치합니다 !
.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*, ...)
두 컴파일러가 옳은 일을 할 수 있도록이 코드를 어떻게 작성해야합니까? 실패하면 명확하고 빠르며 유지 관리 할 수 있도록 어떻게 작성해야합니까?
(1ULL << B) | ... | (1ULL << O)
(1ULL << Constant)
| 각 줄에 상수 이름을 정렬하면 눈에 더 쉬울 것입니다.
int
결과는 비트 연산 의 결과 int
일 수도 있고 long long
값에 따라 달라질 수도 있습니다. 공식적으로 상수 enum
와 동일하지 않습니다 int
. clang은 "as if"를 요구하고 gcc는 현학적 인 상태를 유지합니다
B | D | E | ... | O
? 로 마스크를 구성 할 수 없습니다 .