Как добавить значения от вектора друг к другу

В моем коде я решаю интеграл

y=x^2-4x+6

Я использовал SSE - он позволяет мне работать с 4 значениями за один раз. Я сделал программу, которая решает этот интеграл со значениями от 0 до 5, разделенными на пять 4-элементных векторов n1, n2, n3, n4.

.data
n1: .float 0.3125,0.625,0.9375,1.25
n2: .float 1.5625,1.875,2.1875,2.5
n3: .float 2.8125,3.12500,3.4375,3.75
n4: .float 4.0625,4.37500,4.6875,5
szostka: .float 6,6,6,6
czworka: .float 4,4,4,4
.text
.global main
main:  
        movups (n1),%xmm0

        mulps %xmm0,%xmm0
        movups (szostka),%xmm2
        addps %xmm2,%xmm0
        movups (n1),%xmm1
        movups (czworka),%xmm2
        mulps %xmm2,%xmm1
        subps %xmm1,%xmm0
        movups %xmm0,%xmm7

        movups (n2),%xmm0

        mulps %xmm0,%xmm0
        movups (szostka),%xmm2
        addps %xmm2,%xmm0
        movups (n1),%xmm1
        movups (czworka),%xmm2
        mulps %xmm2,%xmm1
        subps %xmm1,%xmm0
        movups %xmm0,%xmm6

        movups (n3),%xmm0

        mulps %xmm0,%xmm0
        movups (szostka),%xmm2
        addps %xmm2,%xmm0
        movups (n1),%xmm1
        movups (czworka),%xmm2
        mulps %xmm2,%xmm1
        subps %xmm1,%xmm0
        movups %xmm0,%xmm5

        movups (n4),%xmm0

        mulps %xmm0,%xmm0
        movups (szostka),%xmm2
        addps %xmm2,%xmm0
        movups (n1),%xmm1
        movups (czworka),%xmm2
        mulps %xmm2,%xmm1
        subps %xmm1,%xmm0
        movups %xmm0,%xmm4

        mov $1,%eax
        mov $0,%ebx
        int $0x80 

В конце концов, у меня есть 4 вектора в регистрах xmm7, xmm6, xmm5, xmm4. Чтобы решить интеграл, мне нужно добавить векторы друг к другу (что легко), а затем добавить значения из вектора также друг к другу.
Как мне это сделать?

Ответ 1

Как сказал Пол Р в комментарии, вы можете использовать haddps для горизонтальных ops внутри вектора, в конце.

Ваш код выглядит неэффективным. Если вы собираетесь полностью развернуть, вместо использования цикла и аккумулятора вы можете использовать другой регистр в первую очередь для каждой копии вместо того, чтобы иметь movups %xmm0,%xmmX в конце каждого блока.

Также сохраняйте (szostka) и (czworka) в регистре через итерации. Не перезагружайте их каждый раз. Аналогичным образом замените movups (n1),%xmm1 на movups %xmm0, %xmm1 (перед тем, как вы сделаете квадрат %xmm0). На IvyBridge, а затем, этап переименования регистров обрабатывает рег-рег, и они происходят с нулевой задержкой.

Если вам нужно было каждый раз загружать (szostka), было бы лучше использовать addps с операндом памяти вместо отдельного перемещения и добавления. Микро-фьюжн может сохранить эту операцию как единый uop.

Обратитесь http://agner.org/optimize/ к документам о том, как оптимизировать сборку. Возможно, вам будет полезно использовать функции intrinsics, чтобы компилятор позаботился о небольших деталях, таких как распределение регистров, вместо того, чтобы писать в asm напрямую.