История изменений
Исправление LINUX-ORG-RU, (текущая версия) :
А причём тут настоящий sse4? Суть в том чтобы исполнить тоже самое но просто на других инструкциях, это просто пример. Вот есть
pmaxud %xmm0 %xmm1
pminud %xmm0 %xmm1
Можно это перехватить и обработать вот так (тут на ssse3_t не гляди)
void pmaxud(ssse3_t *this)
{
uint32_t * temp1 = this->src.uint32;
uint32_t * temp2 = this->dst.uint32;
this->res.int32[0] = (temp1[0] > temp2[0]) ? temp1[0] : temp2[0];
this->res.int32[1] = (temp1[1] > temp2[1]) ? temp1[1] : temp2[1];
this->res.int32[2] = (temp1[2] > temp2[2]) ? temp1[2] : temp2[2];
this->res.int32[3] = (temp1[3] > temp2[3]) ? temp1[3] : temp2[3];
}
void pminud(ssse3_t *this)
{
uint32_t * temp1 = this->src.uint32;
uint32_t * temp2 = this->dst.uint32;
this->res.int32[0] = (temp1[0] < temp2[0]) ? temp1[0] : temp2[0];
this->res.int32[1] = (temp1[1] < temp2[1]) ? temp1[1] : temp2[1];
this->res.int32[2] = (temp1[2] < temp2[2]) ? temp1[2] : temp2[2];
this->res.int32[3] = (temp1[3] < temp2[3]) ? temp1[3] : temp2[3];
}
Или как угодно по иному используя иные инструкции явно, иные, но которые выполнят туже самую работу. Пусть и не напрямую даже. В любом случае тут надо сидеть и корпеть 24/7. Опять же просто подменить инструкции мало, надо ещё выше залезать и менять области туда и как будут загружаться данные.
Это ещё повезёт что будет примерно вот такое (это из теста когда инструкции подменять пытался)
.data
nums0: .long 2, 3, 8, 9
nums1: .long 4, 5, 6, 7
format_str: .asciz "%d, %d, %d, %d\n"
.text
main:
subq $8, %rsp
movaps nums0, %xmm0
movaps nums1, %xmm1
pmaxud %xmm1, %xmm0 # XMM0 = (XMM0 + XMM1) / 2
# XMM0 = 4, 5, 8, 9
# выводим данные на консоль
movd %xmm0, %esi
psrldq $4, %xmm0
movd %xmm0, %edx
psrldq $4, %xmm0
movd %xmm0, %ecx
psrldq $4, %xmm0
movd %xmm0, %r8d
movq $format_str, %rdi
call printf
addq $8, %rsp
ret
А на деле там обычно всё на голову сложнее. Короче, там я просто мысли в слух вещал, интересно, прикольно было бы. Но… тут нужен спец уже во всём этом шарящий на раз два и у него должно быть абсолютно свободное время. По сути нужна бинарная трансляция, не при исполнении, а просто из файла в файл и потом уже запускать.
А из SSE4A
можно использовать LZCNT/POPCNT/EXTRQ/INSERTQ
для реализации того же pmaxud
, вернее через маски и сдвиги в EXTRQ/INSERTQ
выявлять наибольшее и наименьшее число. Та ещё херня получится запутанная, но SIMD. Или надеяться что компилятор сам всё обернёт в ускорянки хостового процессора, но надо код написать так чтобы он смог это сделать, дать ему подсказки так сказать .
Короче чёрт ногу сломит. Пойду извилину расслаблю, на луве попишу.
P.S. Можно сделать финт ушами и использовать аппаратную виртуализацию KVM
и на уровне виртуализации подменять что хочешь и как хочешь без перехвата трапсов ядра и бинарной трансляции, но я только палочкой потыкал, там надо выделять кусок памяти просто туда всё впихивать и от туда этот кусок памяти исполнять попутно манипулируя всем что там есть как угодно, ладно туда что-то обособленное пихнуть, а вот пихнуть туда просто программу… может и можно, но это выше моего понимания как это сделать. Но тоже прикольно было бы. Типа виртуализация для отдельно взятого приложения.
Исходная версия LINUX-ORG-RU, :
А причём тут настоящий sse4? Суть в том чтобы исполнить тоже самое но просто на других инструкциях, это просто пример. Вот есть
pmaxud %xmm0 %xmm1
pminud %xmm0 %xmm1
Можно это перехватить и обработать вот так (тут на ssse3_t не гляди)
void pmaxud(ssse3_t *this)
{
uint32_t * temp1 = this->src.uint32;
uint32_t * temp2 = this->dst.uint32;
this->res.int32[0] = (temp1[0] > temp2[0]) ? temp1[0] : temp2[0];
this->res.int32[1] = (temp1[1] > temp2[1]) ? temp1[1] : temp2[1];
this->res.int32[2] = (temp1[2] > temp2[2]) ? temp1[2] : temp2[2];
this->res.int32[3] = (temp1[3] > temp2[3]) ? temp1[3] : temp2[3];
}
void pminud(ssse3_t *this)
{
uint32_t * temp1 = this->src.uint32;
uint32_t * temp2 = this->dst.uint32;
this->res.int32[0] = (temp1[0] < temp2[0]) ? temp1[0] : temp2[0];
this->res.int32[1] = (temp1[1] < temp2[1]) ? temp1[1] : temp2[1];
this->res.int32[2] = (temp1[2] < temp2[2]) ? temp1[2] : temp2[2];
this->res.int32[3] = (temp1[3] < temp2[3]) ? temp1[3] : temp2[3];
}
Или как угодно по иному используя иные инструкции явно, иные, но которые выполнят туже самую работу. Пусть и не напрямую даже. В любом случае тут надо сидеть и корпеть 24/7. Опять же просто подменить инструкции мало, надо ещё выше залезать и менять области туда и как будут загружаться данные.
Это ещё повезёт что будет примерно вот такое (это из теста когда инструкции подменять пытался)
.data
nums0: .long 2, 3, 8, 9
nums1: .long 4, 5, 6, 7
format_str: .asciz "%d, %d, %d, %d\n"
.text
main:
subq $8, %rsp
movaps nums0, %xmm0
movaps nums1, %xmm1
pmaxud %xmm1, %xmm0 # XMM0 = (XMM0 + XMM1) / 2
# XMM0 = 4, 5, 8, 9
# выводим данные на консоль
movd %xmm0, %esi
psrldq $4, %xmm0
movd %xmm0, %edx
psrldq $4, %xmm0
movd %xmm0, %ecx
psrldq $4, %xmm0
movd %xmm0, %r8d
movq $format_str, %rdi
call printf
addq $8, %rsp
ret
А на деле там обычно всё на голову сложнее. Короче, там я просто мысли в слух вещал, интересно, прикольно было бы. Но… тут нужен спец уже во всём этом шарящий на раз два и у него должно быть абсолютно свободное время. По сути нужна бинарная трансляция, не при исполнении, а просто из файла в файл и потом уже запускать.
А из SSE4A
можно использовать LZCNT/POPCNT/EXTRQ/INSERTQ
для реализации того же pmaxud
, вернее через маски и сдвиги в EXTRQ/INSERTQ
выявлять наибольшее и наименьшее число. Та ещё херня получится запутанная, но SIMD. Или надеяться что компилятор сам всё обернёт в ускорянки хостового процессора, но надо код написать так чтобы он смог это сделать, дать ему подсказки так сказать .
Короче чёрт ногу сломит. Пойду извилину расслаблю, на луве попишу.