为什么此内联程序集中的错误操作无法正常工作
Why the ror op in this inline assembly not working properly?
我已经编写了一个程序来处理以big-endian格式写入磁盘的一些数据,因此该程序需要交换字节才能执行其他操作。在对代码进行分析后,我发现我的字节交换函数占用了30%的执行时间。所以我心想,我该怎么加快速度呢?所以我决定写一小段内联汇编。
我会替换这个:
void swapTwoByte(char* array, int numChunks)
{
for(int i= (2*numChunks-1); i>=0; i-=2)
{
char temp=array[i];
array[i]=array[i-1];
array[i-1]=temp;
}
}
这个:
void swapTwoByte(int16* array, int numChunks)
{
for(int i= (numChunks-1); i>=0; --i)
{
asm("movw %1, %%ax;"
"rorw %%ax;"
"rorw %%ax;"
"rorw %%ax;"
"rorw %%ax;"
"rorw %%ax;"
"rorw %%ax;"
"rorw %%ax;"
"rorw %%ax;"
"movw %%ax, %0;"
: "=r" ( array[i] )
: "r" (array[i])
:"%ax"
);
}
}
它完成了预期的工作,但这是大量的轮换操作。
所以我的问题是:根据这个源,rorw可以取两个操作数,在gas系统中,源操作数应该是要旋转的位数,但每次我试图用之类的东西替换8个旋转权的列表时
".set rotate, 0x0008"
"rorw rotate, %%ax"
我收到一个汇编程序错误:
"Error: number of operands mismatch for `ror'"
为什么会这样?我错过了什么?
首先,使用
#include <arpa/inet.h>
little_endian = ntohs(big_endian);
这将在您使用的任何系统上编译成最佳代码,即使您碰巧将代码移植到big-endian平台,它也会起作用。
但是,这不会解决您的性能问题,因为我认为您已经错误地识别了问题。尼莫的第一条微观优化法则是:"数学很快,记忆力很慢"。
遍历一大块内存并交换其字节对缓存极不友好。字节交换是一个循环;一次内存读取或写入需要数百个周期,除非它在缓存中命中。
因此在使用字节之前不要交换字节。我个人最喜欢的方法是:
class be_uint16_t {
public:
be_uint16_t() : be_val_(0) {
}
be_uint16_t(const uint16_t &val) : be_val_(htons(val)) {
}
operator uint16_t() const {
return ntohs(be_val_);
}
private:
uint16_t be_val_;
} __attribute__((packed));
这定义了一个两字节的类,表示内存中的大端数。它根据需要隐式地向uint16_t进行强制转换和从uint16_t进行强制类型转换。因此,将内存指针投射到be_uint16 *
,然后像数组一样访问它;忘记字节交换吧,因为类会为你做这件事:
const be_uint16_t *p = (be_uint16 *)my_block;
unsigned val = p[37]; // or whatever
注意,你甚至可以这样做:
be_uint16_t x = 12;
x = x + 1;
write(fd, &x, sizeof(x)); // writes 13 to file in big-endian form
根据我的经验,在使用前立即交换值的开销是无法检测的。Locality是游戏的名称。。。
考虑重新组织一下C++代码。正如所写的,g++4.5.2为我编译了一个无聊的紧密循环,其中有四个8位mov
和两个指针递减。
.L3:
movzbl (%rdi), %eax
movzbl -1(%rdi), %edx
movb %al, -1(%rdi)
movb %dl, (%rdi)
subq $2, %rdi
subl $2, %esi
jns .L3
将其重写为
void swapTwoByte(char* array, int numChunks)
{
for(int i = 0; i<numChunks*2; i+=2)
std::swap(array[i], array[i+1]);
}
让编译器意识到你在做什么,并打开SIMD的全部功能,核心循环现在一次处理32个字节:
.L4:
movdqu (%rdx), %xmm1
movdqu (%rax), %xmm2
movdqa %xmm1, %xmm0
movdqa %xmm2, %xmm3
pshufb %xmm7, %xmm0
pshufb %xmm4, %xmm2
pshufb %xmm6, %xmm3
pshufb %xmm5, %xmm1
por %xmm3, %xmm0
por %xmm2, %xmm1
incl %ecx
movdqa %xmm1, %xmm2
punpckhbw %xmm0, %xmm1
punpcklbw %xmm0, %xmm2
movdqu %xmm2, (%rdx)
movdqu %xmm1, (%rax)
addq $32, %rdx
addq $32, %rax
cmpl %ecx, %r8d
ja .L4
一个CCD_ 3不会打败它。
Swap指令适用于32位值。要交换word中的两个字节,请使用xchg-al,ah指令。
- QSqlquery prepare()和bindvalue()不工作
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++为线程工作动态地分割例程
- 为什么我的 std::ref 无法按预期工作?
- 布尔比较运算符是如何在C++中工作的
- SampleConsensusPrerejective(ext.RANSAC)是如何真正工作的
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- <<操作员在下面的行中工作
- 有人能解释一下为什么下界是这样工作的吗C++的
- ExtractIconEx:可以工作,但偶尔会崩溃
- C++中的memset函数工作不正常
- 当我在第一个循环中使用"auto"时,它工作正常,但是使用"int"它会给出错误,为什么?
- 为什么STD ::计数将常数传递给Lambda,而不是在弦上工作时而不是字符
- C++程序已停止工作-求解常微分方程