Код: Выделить всё
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 (но я думаю, это нормально).
Со всеми Имейте в виду вышесказанное: существует ли более быстрый/более приятный/более предсказуемый способ сложения этих чисел?
Подробнее здесь: https://stackoverflow.com/questions/785 ... ll-numbers