gpt4 book ai didi

c++ - 我可以让 C++ 在没有内联汇编的情况下生成 cmpps 指令吗?

转载 作者:太空狗 更新时间:2023-10-29 20:37:11 25 4
gpt4 key购买 nike

我希望现代 C++ 编译器能够生成最快的机器代码。还是我们会在 2016 年继续使用内联汇编?我需要搜索与一个特定框相交的浮点 3D 边界框。我对汇编版本的想法是

1. cmpps => register A
2. cmpss => register B
3. C = A & B
4. convert C into "normal" register
5. compare it with zero
6. conditionally jump

即使在使用第 4 个 float 填充结构后,GCC 4.4 和 Visual Studio Comunity 2015 也仅使用 comiss 指令一次生成一个 float 比较。是否需要特定的 C++ 表达式顺序或这些编译器无法自行优化它?

我的测试用例:

struct Vec
{
float x,y,z,w;
};

struct BBox
{
Vec min,max;
};

bool bbox(BBox& b, Vec& v)
{
return
b.min.x <= v.x && v.x <= b.max.x &&
b.min.y <= v.y && v.y <= b.max.y &&
b.min.z <= v.z && v.z <= b.max.z &&
b.min.w <= v.w && v.w <= b.max.w;
}

int main()
{
BBox b;
Vec v;
return bbox(b, v);
}

最佳答案

可惜 gcc/clang 没有自动矢量化它,因为它是 pretty easy :

// clang doesn't let this be a constexpr to mark it as a pure function :/
const bool bbox(const BBox& b, const Vec& v)
{
// if you can guarantee alignment, then these can be load_ps
// saving a separate load instruction for SSE. (AVX can fold unaligned loads)
// maybe make Vec a union with __m128
__m128 blo = _mm_loadu_ps(&b.min.x);
__m128 bhi = _mm_loadu_ps(&b.max.x);
__m128 vv = _mm_loadu_ps(&v.x);

blo = _mm_cmple_ps(blo, vv);
bhi = _mm_cmple_ps(vv, bhi);
__m128 anded = _mm_and_ps(blo, bhi);

int mask = _mm_movemask_ps(anded);
// mask away the result from the padding element,
// check that all the bits are set
return (mask & 0b0111) == 0b0111;
}

编译为

    movups  xmm0, xmmword ptr [rdi]
movups xmm1, xmmword ptr [rdi + 16]
movups xmm2, xmmword ptr [rsi]
cmpleps xmm0, xmm2
cmpleps xmm2, xmm1
andps xmm2, xmm0
movmskps eax, xmm2
and eax, 7
cmp eax, 7
sete al
ret

如果您反转比较的意义 (cmpnle),以测试是否在任何轴上的边界框之外,您可以做类似的事情

int mask1 = _mm_movemask_ps(blo);
int mask2 = _mm_movemask_ps(bhi);
return !(mask1 | mask2);

可能会编译成

movmsk
movmsk
or
setnz

所以整数测试更便宜,你用另一个 movmsk 替换一个 vector AND(大约相同的成本)。

我想了一会儿,这样做意味着 NaN 算作在框内,但实际上 cmpnleps 在 NaN 中的一个操作数时为真。 (在这种情况下 cmpleps 是错误的,所以它确实是相反的)。

我还没有想清楚在这种情况下填充会发生什么。它最终可能会变成 !((mask1|mask2) & 0b0111),这对于 x86 仍然更有效,因为 test 指令免费执行 AND,并且可以在 Intel 和 AMD 上使用分支指令进行宏融合。

movmskps 在 AMD 上是 2 m-ops 和高延迟,但使用 vector 可能仍然是一个胜利。两个 movmskps 指令在 AMD 上可能比我首先发布的代码稍差,但它是流水线的,因此它们都可以在 cmpps 指令完成后传输。

关于c++ - 我可以让 C++ 在没有内联汇编的情况下生成 cmpps 指令吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35693277/

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