使用汇编代码从内存复制到c++中的寄存器
copy from memory to register in c++ using assembly code
我在将c++程序转换为程序集时遇到问题我必须为做
这是我的c++代码
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进行比较,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
别名另一个指针,它会做一些与原来不同的事情。
我假设您使用的是最新的英特尔芯片。。。我认为你真正想使用的是(如果用Cray:-来形容的话,相当有限)向量功能,这些被称为AVX。还有一些库可以在C/C++下做到这一点,从谷歌搜索AVX和C.开始
话虽如此,您还可以告诉编译器使用"register"关键字将一些变量存储在寄存器中,请参阅C++中的register关键字
- 本质:使用__128寄存器
- 将寄存器设计成可由C和C++访问的外设的最佳实践
- 在模拟器中使用并集来模拟CPU寄存器有多合适
- 使用英特尔 PIN 修改寄存器
- AVX 指令中寄存器和指针之间的客观差异
- 如何确定我的处理器有多少个 AVX 寄存器?
- 除非使用某些寄存器,否则函数挂钩会崩溃
- 寄存器上的管道计算
- 其中关于内存和寄存器的左值和右值
- 有没有办法强制C++编译器将变量存储在寄存器中?
- "变量":函数中函数作用域不允许初始化的自动或寄存器变量'naked'
- Atmel Studio:返回一个包含数组的寄存器
- 使用 googletest 测试嵌入式C++代码时处理外设寄存器的重复符号
- 移位寄存器74HC595输出电流
- 超过255的Modbus寄存器无法访问SimpleModbus
- 如何在程序集函数中将元素数组作为参数传递时转发 ARM 寄存器的地址指针
- xmm 寄存器中的__m128何时?
- 是否可以在 GCC 中使用带有 C++17 的显式寄存器变量?
- 处理器寄存器的大小是多少,有多少个处理器寄存器?
- 使用 Windows 寄存器查找下一个"Daylight Saving Time"