- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
void add_SSE(uint8_t a[static 7], uint8_t b[static 7], uint8_t out[static 7])
{
uint64_t a_64 = 0;
uint64_t b_64 = 0;
for (size_t i = 0; i < 7; i++) // можно наанроллить
{
a_64 |= (uint64_t)a[i] << (i*9);
b_64 |= (uint64_t)b[i] << (i*9);
}
uint64_t c_64 = a_64 + b_64;
for (size_t i = 0; i < 7; i++) // можно наанроллить
{
out[i] = (uint64_t)c_64 >> (i*9);
}
}
Follow us!
https://wandbox.org/permlink/y5oFcXGjMxDTh5KW
1. Упаковка для побитовых операций.
2. Упаковка для сложения: каждое число будет расширено на один бит.
Последний вариант ещё может быть знаковым и беззнаковым.
А ещё можно упаковать для умножения на скаляр, тогда каждое число будет расширено в два раза.
P.S. Тут чувак накостылил __int128 через перегрузку операторов:
https://stackoverflow.com/a/37907522
Лучше б сделали тупо произвольно-длинную арифметику, потом бы запилили специализацию под конечный размер. И тогда для произвольно-длинной арифметики можно было б сделать всякие умные оптимизации, типа
Только вот это нихера не выйдет с говном, которое есть в крестопомойной параше (разве что компилятор допилить специально под эту дрисню). Шаблонами нельзя определять всякие свойства коммутативности, ассоциативности и стратегии оптимизации.
>> В частности, комиссия всё-таки попросила в wide_int оперировать количеством машинных слов.
Вот уроды. Они хотят, чтобы при перекококомпиляции на другой платформе программа оперировала числами другого размера? Т. е. опять придётся потеть с мокросами и ифдефами?
Из 64-битного MSVC убрали встроенный асм, так что приходится использовать интринсики. Интринсики –— хорошая штука, так как на первый взгляд позволяют писа́ть код, не привязанный к кокококонкретному процессору. Однако, они оказались привязанными к кокококомпилятору:
Причём даже семантика не совпадает:
Полная жопа, короче.
Оператор in выполняется через инструкции BT и SETC. Вот с добавлением элемента хуже (оптимизатор не хочет выкидывать call fpc_varset_add_sets; видимо, задел для больших множеств) и цикл не хочет выкидывать, хотя задача должна решаться одной итерацией. Оптимизатор –— питух.
«GPC» (ныне заброшен) использует вызов библиотечной функции (call __p_set_in).
«TMT Pascal» (похоже, что тоже заброшен) тоже всё делает через вызов библиотечных функций и инлайнить не хочет.
«WDSibyl» мне не удалось даже запустить.
Компиляторы, основанные не на «Object Pascal», а на «Standard Pascal» или «Extended Pascal», я не тестировал.
Итого: ныне развивающиеся компиляторы в нативный код («Delphi» и «FPC») при работе со множествами из специнструкций используют только BT.
https://lleo.me/arhive/esse/os2.htm
Самое страшное, что и про резину 36-й и 17-й версии я понял, и про Даниэлу...
WCT Pascal
Фигню написал. Надо просто tempset := tempset + [n]. Сдвиг не нужен.
Всё равно использует только BT, а установку/сброс делает через сдвиг + OR/XOR.
Хотя тут теперь два сложения на 8 элементов (против одного сложения на 7 элементов), думаю что на сдвигах проебется больше времени.
Вот это СИМД!
SBB r8
Одна операция надо всеми элементами массива — SIMD (single instruction, many data). Реальные примеры — SSE, MMX.
Несколько разных операций, каждая над скаляром — MISD. Реальный пример — VLIW (Итаниум, Эльбрус).
Несколько разных инструкций над массивами — MIMD. Это уже какие-нибудь DSP, GPU.
MIMD — multiple instruction, multiple data. Это скорее SMP, NUMA. В GPU SIMT — single instruction, multiple threads.
Сопроцессор фирмы «Крей» сюда подходит?
А если у меня один сокет то это уже не MIMD?
Для полноты, чтобы покрыть гипотетический случай двух одноядерных процессоров в двух сокетах.
> А если у меня один сокет то это уже не MIMD?
Если в твой сокет воткнут одноядерный процессор, то это single instruction single data. Если многоядерный, то MIMD.
inb4: а что насчёт hyper-threading??
Отнябись.
нет нет нет ты меня не наебеш
Сейчас есть термины:
1. гнездо/сокет (дома их обычно 1, на сервере может быть 2) и именно там NUMA
2. ядра (ядер обычно много если у тебя процессор после 2006-го года
выпущен)
3. потоки (тот самый гипер-трединг)
Ядра одного процессора тоже могут одновременно выполнять разную инструкцию. Тоже ``multiple instruction''.
Single instruction multiple X — это когда над группой данных одновременно выполняют одну и ту же инструкцию. К примеру, одна инструкция AVX может выполнять сложение нескольких чисел. Все треды в одном warp на GPU тоже всегда выполняют одну и ту же инструкцию, fetch там или арифметику, потому что у них тупо расшарен program counter и вся машинерия, связанная с планированием исполнения. IF/ELSE там забавно работает, все треды всегда выполняют все ветки, но сайд-эффекты маскируются в зависимости от выполнения условия. Поэтому SIMT.
А MISD — это экзотическая питушня вроде серверов, которые вычисляют одно и то же на двух ядрах, а потом сравнивают, чтобы отловить возможные сбои.
...Без SSE и AVX. С ними может быть SIMD. В общем, это довольно условное разделение.
Не вырвал клок волос,
Как телеграф известие
Такое вот принес,
Что немцы храбро заняли
Пункт важный и большой
И утвердили в Африке
Права страны родной…
С тех пор в Берлине стар и млад
Одно лишь и твердят:
Нах Африка, нах Африка,
Нах Камерун
Так немцы говорят