Код: Выделить всё
void add16_reference (uint8_t *as, uint8_t *bs) {
for (auto i = 0; i < 16; i++) {
as[i] += bs[i];
}
}
Код: Выделить всё
typedef unsigned __int128 uint128_t;
void add16_v3 (uint8_t *as, uint8_t *bs) {
uint128_t a, b, s;
std::memcpy(&a, as, 16);
std::memcpy(&b, bs, 16);
s = a + b;
std::memcpy(as, &s, 16);
}
Я решил, что могу использовать одно сложение, потому что знаю, что отдельные суммы всегда умещаются в байт.
Я использовал godbolt (благослови их Господь) ) для проверки полученного кода https://godbolt.org/z/h4adMTnKn; Я вижу, что иногда компиляторы выдают инструкции SIMD (?), а иногда нет. Это важно, поскольку в тестах с использованием старых добрых movs/adds происходит ~8 раз быстрее https://quick-bench.com/q/z0374AXew8_eL8eDoQXn9XlJm9g
Мне также кажется, что нет верный способ убедить компиляторы оптимизировать тем или иным способом (см., что v1 компилируется в movs/adds на godbolt, а на Quickbench вместо этого используется simd).
Другие вещи, которые я пробовал: использование reinterpret_cast вместо memcpy - но это генерирует инструкции для просмотра SIMD, независимо от того, как я их перетасовываю; Кроме того, просто добавление ограничения в as и bs (на этот раз в C) к эталонной реализации, похоже, всегда выдает simds (но я думаю, это нормально).
Со всеми Имейте в виду вышеизложенное: существует ли более быстрый/более приятный/более предсказуемый способ сложения этих чисел?
РЕДАКТИРОВАТЬ: Спасибо @Jan за указание на то, что тесты неправильно. Возможно, эта обновленная версия https://quick-bench.com/q/EMyFsTi7w8wKx4lO_EPQg_FvVb0 верна
Подробнее здесь: https://stackoverflow.com/questions/785 ... ll-numbers