у меня проблема при преобразовании программы на С ++ в сборку
я должен сделать это для
вот мой код с ++
for(int i=0;i<rows-4;i++,a+=4,b+=4,c+=4,d+=4,e+=4,f+=4,x+=4,o+=4){
for(int j=0;j<cols-4;j++,a++,b++,c++,d++,e++,f++,x++,o++){
*o=*a>*x;
*o=*b>*x|(*o<<1);
*o=*c>*x|(*o<<1);
*o=*d>*x|(*o<<1);
*o=*e>*x|(*o<<1);
*o=*f>*x|(*o<<1);
}
}
o — указатель для выходных данных, в то время как a, b, c, d, e, f и x — указатель на входные данные. я хочу просто сохранить сравнения из входных данных в одной переменной, но приведенный выше код неэффективен, когда обрабатываемые данные большие. Программе нужно больше раз сохранять данные в памяти по сравнению с сохранением временных данных в регистре.
так что я хочу сделать это просто сделать этот процесс в реестре. Я попытался сохранить данные, на которые ссылается x, в EBX, сравнить EBX с ECX, которые содержат значение, на которое ссылается a (и b, c, d, e, f, последовательно), сохранить результат сравнения в EAX и сдвиг EAX регистр слева, так что все сравнения будут храниться в одной переменной. после того, как все 6 сравнений уже обработаны, значение из ECX копируется в память.
вот что я сделал, моя программа может работать в два раза быстрее, но все значения, которые я получаю, равны нулю. может я ошибаюсь?
__asm__(
"xorl %%eax,%%eax;""xorl %%ebx,%%ebx;""xorl %%ecx,%%ecx;"
"movl %1, %%ebx;"
//start here
"movl %2,%%ecx;""cmp %%ebx,%%ecx;""jnz .one;""orl $0x1,%%eax;"
".one:;""shll $1,%%eax;""movl %3,%%ecx;""cmp %%ebx,%%ecx;""jnz .two;""orl $0x1,%%eax;"
".two:;""shll $1,%%eax;""movl %4,%%ecx;""cmp %%ebx,%%ecx;""jnz .three;""orl $0x1,%%eax;"
".three:;""shll $1,%%eax;""movl %5,%%ecx;""cmp %%ebx,%%ecx;""jnz .four;""orl $0x1,%%eax;"
".four:""shll $1,%%eax;""movl %6,%%ecx;""cmp %%ebx,%%ecx;""jnz .five;""orl $0x1,%%eax;"
".five:""shll $1,%%eax;""movl %7,%%ecx;""cmp %%ebx,%%ecx;""jnz .six;""orl $0x1,%%eax;"
".six:"//output
"movl %%eax,%0;"
:"=r"(sett)
:"r"((int)*x),"r"((int)*a) ,"r"((int)*b) ,"r"((int)*c) ,"r"((int)*d),"r"((int)*e),"r"((int)*f) /* input */
);
Несколько вариантов:
1) Выбросьте свой код сборки ручной сборки. Вы сказали, что код на C медленный, расскажите нам, насколько. Я не вижу, как можно было бы измерить разницу каким-либо значимым образом, поскольку версия asm даже не дает правильного результата. Поставь по другому, попробуй asm("nop;");
Это еще более быстрый способ получить неправильный результат.
2) Перепишите ваш код на C, чтобы прочитать *x
только однажды; сохранить результат во временной переменной и писать только в *o
в конце.
3) Если это соответствует вашей семантике (и поддерживается вашим компилятором), украсьте ваши указатели с помощью restrict
/__restrict
/__restrict__
(из C99, обычно доступен в C ++ как расширение), поэтому компилятор не знает, что ни одна из входных переменных не изменяется при записи в *o
,
4) Компиляторы достаточно хороши в автоматическом развертывании циклов. Это может потребовать комбинации параметров командной строки, #pragma
директивы или расширение / атрибуты.
Вот что я имею в виду, переписав его, чтобы использовать временные:
for(int i=0;i<rows-4;i++,a+=4,b+=4,c+=4,d+=4,e+=4,f+=4,x+=4,o+=4){
for(int j=0;j<cols-4;j++,a++,b++,c++,d++,e++,f++,x++,o++){
uint32_t tmp_x = *x;
*o = (*a > tmp_x ? 0x20 : 0)
| (*b > tmp_x ? 0x10 : 0)
| (*c > tmp_x ? 0x08 : 0)
| (*d > tmp_x ? 0x04 : 0)
| (*e > tmp_x ? 0x02 : 0)
| (*f > tmp_x ? 0x01 : 0);
}
}
Что это меняет? На оригинальной версии, x
читается в каждом задании. Компилятор этого не знает o
а также x
указать на разные места; в худшем случае компилятор должен читать из x
снова каждый раз, потому что, написав o
, значение в x
может меняться
Конечно, этот код имеет другую семантику: если вы действительно позволяете o
псевдоним любого другого указателя, он будет делать что-то отличное от оригинала.
Я предполагаю, что вы используете новейший чип Intel. … и я думаю, что вы действительно хотите использовать (довольно ограниченный, если использовать, скажем, векторные возможности Cray :-), они называются AVX. Есть также библиотеки, которые будут делать это в C / C ++, начните с поиска в Google AVX и C.
Сказав это, вы также можете указать компилятору сохранить некоторые переменные в регистрах, используя ключевое слово «register», см. Это Зарегистрировать ключевое слово в C ++