gpt4 book ai didi

c++ - 为什么会出现这些汇编错误?

转载 作者:塔克拉玛干 更新时间:2023-11-03 06:45:30 25 4
gpt4 key购买 nike

我有一个大函数,需要在某个点将 float 转换为整数。如果没有这种转换,函数在我的机器上需要 11-12 ns/loop。转换需要大约 400 ns/循环。

阅读一些内容后,我找到了一种使用内联汇编来加快转换速度的方法。我的函数的第一次迭代如下:

inline int FISTToInt (float f)
{
int i;
asm("fld %1;"
"fistp %0;"
:"=r" ( i )
:"r" ( f )
:
);
return i;
}

编译时出现以下错误:

src/calcRunner.cpp: Assembler messages:
src/calcRunner.cpp:43: Error: operand type mismatch for `fld'
src/calcRunner.cpp:43: Error: operand type mismatch for `fistp'

稍微想了想,忘记了指令后缀,所以把函数改成如下:

inline int FISTToInt (float f)
{
int i;
asm("flds %1;"
"fistps %0;"
:"=r" ( i )
:"r" ( f )
:
);
return i;
}

但是这并没有解决问题,而是我得到了这个:

src/calcRunner.cpp: Assembler messages:
src/calcRunner.cpp:43: Error: invalid instruction suffix for `fld'
src/calcRunner.cpp:43: Error: invalid instruction suffix for `fistp'

这是怎么回事?

最佳答案

这个有效:

int trunk(float x)
{
int i;
__asm__ __volatile__(
" flds %1\n"
" fistpl %0\n"
: "=m"(i) : "m"(x));
return i;
}

但是,如果您实际使用 x87 模式,它只(可能)比编译器生成的代码快,而且它更快是因为它不加载和存储确定舍入的 FP 控制字。我将返回几个基准...

简单的基准测试:

#include <stdio.h>
#include <stdlib.h>

int trunk(float x)
{
int i;
__asm__ __volatile__(
" flds %1\n"
" fistpl %0\n"
: "=m"(i) : "m"(x));
return i;
}


int trunk2(float x)
{
return (int)x;
}

inline long long rdtsc()
{
unsigned long a, d;
__asm volatile ("rdtsc" : "=a" (a), "=d" (d) : : "ebx", "ecx");
return a | ((long long)d << 32);
}


int main()
{
float f[1000];
for(int i = 0; i < 1000; i++)
{
f[i] = rand() / (i+1);
}
long long t = rdtsc();
int sum = 0;
for(int i = 0; i < 1000; i++)
{
sum = trunk(f[i]);
}
t = rdtsc() - t;
printf("Sum=%d time=%ld\n", sum, t);

t = rdtsc();
sum = 0;
for(int i = 0; i < 1000; i++)
{
sum = trunk2(f[i]);
}
t = rdtsc() - t;
printf("Sum=%d time=%ld\n", sum, t);

return 0;
}

用 gcc -O2 -m64 -std=c99 编译,结果如下:

Sum=1143565 time=30196
Sum=1143565 time=15946

在 32 位编译中 (gcc -O2 -m32 -std=c99):

Sum=1143565 time=29847
Sum=1143565 time=107618

换句话说,它慢了很多。但是,如果我们启用 sse2(并删除:gcc -m32 -msse2 -mfpmath=sse -O2,它会变得更好:

Sum=1143565 time=30277
Sum=1143565 time=11789

请注意,第一个数字是“您的解决方案”,其中第二个结果是编译器的解决方案。

显然,请对您的系统进行测量,以确保结果确实匹配。

编辑:在发现我实际上应该在循环中添加数字,而不是仅仅遍历它们并将它们放入 sum 之后,我得到以下 clang 结果:

clang -m32 -msse2 -mfpmath=sse -O2 floatbm.c -std=c99

Sum=625049287 time=30290
Sum=625049287 time=3663

为什么“让编译器完成工作”要好得多的解释是,Clang 3.5 正在为第二个循环生成一个具有适当 SSE simd 的展开循环——它不能为第一个循环执行此操作,所以每次迭代都是 1 个浮点值。

为了表明 gcc 仍然给出相同的结果,我用 gcc 重新运行:

Sum=625049287 time=31612
Sum=625049287 time=15007

与之前唯一不同的是,我使用了 sum += trunk(f[i]); 而不是 sum = ...

关于c++ - 为什么会出现这些汇编错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22392413/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com