LINUX.ORG.RU

История изменений

Исправление 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. Или надеяться что компилятор сам всё обернёт в ускорянки хостового процессора, но надо код написать так чтобы он смог это сделать, дать ему подсказки так сказать .

Короче чёрт ногу сломит. Пойду извилину расслаблю, на луве попишу.