XCode и функция _bittest - PullRequest
       21

XCode и функция _bittest

0 голосов
/ 13 июня 2018

У меня есть небольшой проект C ++, который был разработан для Win32, и я хочу перенести его на OSX.В коде используются такие функции, как _bittest и _bittest64, но я не нашел таких же функций в заголовочных файлах XCode.

Что может быть альтернативой этим функциям?Может быть, есть хорошие рабочие полифилы.Проект действительно унаследован, на данный момент никаких дополнительных действий не требуется.

1 Ответ

0 голосов
/ 13 июня 2018

Символы _bittest и _bittest64 являются внутренними компонентами компилятора, которые испускают инструкции битового теста , в частности x86 bt, для проверки значения битас индексом, начинающимся с нуля.

С операндом памяти, bt имеет поведение цепочки сумасшедших CISC, где битовый индекс может выходить за пределы dword / qword памяти, выбранного режимом адресации.Это медленно и поэтому компиляторы сначала загружают операнд в регистр.Но это то, что присуще MSVC.В противном случае он не должен быть встроенным.

Следующий C ++ соответствует поведению регистровой версии инструкции bt, заключая счетчик сдвига в ширину регистра, то есть эффективно просматривая толькомладшие биты.( Это соответствует внутреннему MSVC , если b <32 или <64 </em>. ). См. Обновленный код и комментарии для обсуждения того, как реализовать семантику MSVC, которая позволяет ему получать доступ извнеlong или long long.

Также следует помнить, что long является 32-разрядным типом в x64 Windows ABI, но 64-разрядным типом в x86-64 System V ABI(который вы используете в OS X, если вы не создаете устаревший 32-битный код).Вы можете изменить свой код на int32_t или uint32_t, чтобы не оставлять неиспользуемые биты в каждом long, в зависимости от того, как вы его используете.

inline
unsigned char bittest(long const *a, long b)
{
    auto const value{ *a };
    auto const mask{ 1L << (b&31) };
    auto const masked_value{ value & mask };
    return unsigned char{ masked_value != 0 };
}

inline
unsigned char bittest64(long long const *a, long long b)
{
    auto const value{ *a };
    auto const mask{ 1LL << (b&63) };
    auto const masked_value{ value & mask };
    return unsigned char{ masked_value != 0 };
}

Я не в курселюбые встроенные функции GCC или Clang с идентичной функциональностью.При необходимости вы можете вместо этого прибегнуть к генерации инструкций по сборке из реализаций функций, но bt с операндом памяти медленен, поэтому обычно лучше всего реализовать его на чистом C ++ и позволить компилятору делать хорошую работу.

Обновление:

После обсуждения кода, испускаемого внутренними компонентами, стало ясно, что предложенный ранее код замены охватывает только часть функциональности.В частности, встроенные функции позволяют индексировать биты вне памяти, занимаемой *a.Следующие реализации также учитывают это.

inline
unsigned char bittest(std::int32_t const *a, std::int32_t b)
{
    auto const bits{ reinterpret_cast<unsigned char const*>(a) };
    auto const value{ bits[b >> 3] };
    auto const mask{ (unsigned char)(1 << (b & 7)) };
    return (value & mask) != 0;
}

inline
unsigned char bittest64(std::int64_t const *a, std::int64_t b)
{
    auto const bits{ reinterpret_cast<unsigned char const*>(a) };
    auto const value{ bits[b >> 3] };
    auto const mask{ (unsigned char)(1 << (b & 7)) };
    return (value & mask) != 0;
}
...