_addcarry_u64 и _addcarryx_u64 с MSVC и ICC
MSVC и ICC поддерживают встроенные _addcarry_u64
и _addcarryx_u64
.
В соответствии с Intel Intrinsic Guide и белая бумага должен отображаться на adcx
и adox
соответственно. Однако, посмотрев на сгенерированную сборку, ясно, что они сопоставляются с adc
и adcx
соответственно, и нет никакого внутреннего, который отображается на adox
.
Кроме того, сообщая компилятору о включении AVX2 с /arch:AVX2
в MSVC или -march=core-avx2
с ICC на Linux, не имеет значения.
Я не уверен, как включить ADX с MSVC и ICC.
Документация для MSVC содержит список _addcarryx_u64
с технологией ADX, тогда как _addcarry_u64
не имеет перечисленных технологий. Тем не менее, ссылка в документации MSVC для этих встроенных функций напрямую связана с руководством Intel Intrinsic, которое противоречит собственно документации MSVC и сгенерированной сборке.
Из этого я пришел к выводу, что Intel Intrinsic guide и белая бумага ошибочны.
Это означает, что MSVC считает, что он не позволяет встроенную сборку, он должен предоставить способ использования adc
, который он выполняет с помощью _addcarry_u64
.
Одним из больших преимуществ adcx
и adox
является то, что они работают с разными флагами (переносят CF
и overflow OF
), что позволяет использовать две независимые параллельные цепи переноса. Однако, поскольку для adox
нет неотъемлемой возможности, как это возможно? С ICC по крайней мере можно использовать встроенную сборку, но это невозможно с MSVC в 64-битном режиме.
Документация Microsoft и Intel (как белая бумага, так и встроенный гид онлайн) соглашаются теперь.
Внутренняя документация _addcarry_u64
говорит только о adc
. Внутренний _addcarryx_u64
может создавать либо adcx
, либо adox
. Однако с MSVC 2013 и 2015, _addcarryx_u64
создает adcx
. ICC производит оба.
Ответы
Ответ 1
Они отображаются на adc
, adcx
AND adox
. Компилятор решает, какие инструкции использовать, в зависимости от того, как вы их используете. Если вы выполняете два добавления большого числа параллельно, компилятор будет использовать adcx
и adox
для большей пропускной способности. Например:
unsigned char c1 = 0, c2 = 0
for(i=0; i< 100; i++){
c1 = _addcarry_u64(c1, res[i], a[i], &res[i]);
c2 = _addcarry_u64(c2, res[i], b[i], &res[i]);
}
Ответ 2
Соответственно, GCC не поддерживает ADOX и ADCX на данный момент. "В настоящий момент" включает GCC 6.4 (Fedora 25) и GCC 7.1 (Fedora 26). GCC эффективно отключает встроенные функции, но он все еще рекламирует поддержку, определяя __ADX__
в препроцессоре. Также см. Проблема 67317, создание глупого кода для _addcarry_u32/_addcarry_u64. Большое спасибо Xi Ruoyao за обнаружение проблемы.
Согласно Uros Bizjak в списке рассылки справки GCC, GCC может никогда не поддерживать внутренние функции. Также см. GCC не генерирует ADCX или ADOX для _addcarryx_u64.
У Clang есть свой набор проблем в отношении ADOX и ADCX. Clang 3.9 и 4.0 при попытке их использования. Также см. Проблема 34249, Паника при использовании _addcarryx_u64 с Clang 3.9. Согласно Крейгу Топперу, это должно быть исправлено в Clang 5.0.
Приношу свои извинения за отправку информации по запросу MSVC. Это один из немногих ударов при поиске информации об использовании встроенных функций.