_MM_TRANSPOSE4_PS 导致 GCC 中的编译器错误?
Posted
技术标签:
【中文标题】_MM_TRANSPOSE4_PS 导致 GCC 中的编译器错误?【英文标题】:_MM_TRANSPOSE4_PS causes compiler errors in GCC? 【发布时间】:2014-08-18 09:42:39 【问题描述】:我第一次在 GCC 而不是 MSVC 中编译我的数学库,并经历了所有的小错误,我遇到了一个根本没有意义的错误:
Line 284: error: lvalue required as left operand of assignment
第 284 行是什么?这个:
_MM_TRANSPOSE4_PS(r, u, t, _mm_setr_ps(0.0f, 0.0f, 0.0f, 1.0f));
(r, u, t 都是__m128
的实例)
熟悉使用xmmintrin.h
的人会知道_MM_TRANSPOSE4_PS
实际上并不是一个函数,而是一个宏,它扩展为:
/* Transpose the 4x4 matrix composed of row[0-3]. */
#define _MM_TRANSPOSE4_PS(row0, row1, row2, row3) \
do \
__v4sf __r0 = (row0), __r1 = (row1), __r2 = (row2), __r3 = (row3); \
__v4sf __t0 = __builtin_ia32_unpcklps (__r0, __r1); \
__v4sf __t1 = __builtin_ia32_unpcklps (__r2, __r3); \
__v4sf __t2 = __builtin_ia32_unpckhps (__r0, __r1); \
__v4sf __t3 = __builtin_ia32_unpckhps (__r2, __r3); \
(row0) = __builtin_ia32_movlhps (__t0, __t1); \
(row1) = __builtin_ia32_movhlps (__t1, __t0); \
(row2) = __builtin_ia32_movlhps (__t2, __t3); \
(row3) = __builtin_ia32_movhlps (__t3, __t2); \
while (0)
那么...是什么导致我的编译器错误?我不在这里重新定义任何我知道的东西。当我使用 MSVC 时,这个完全相同的代码编译并运行得非常好。
【问题讨论】:
显然_mm_setr_ps(0.0f, 0.0f, 0.0f, 1.0f)
不会扩展为左值。
这是 C 代码还是 C++ 代码?
代码sn-p是C++。
我在您的问题中添加了 visual-c++ 和内在标记。这确实是 MSVC 的问题,而不是 GCC 的问题。
【参考方案1】:
你需要改变:
_MM_TRANSPOSE4_PS(r, u, t, _mm_setr_ps(0.0f, 0.0f, 0.0f, 1.0f));
到:
__m128 v = _mm_setr_ps(0.0f, 0.0f, 0.0f, 1.0f);
_MM_TRANSPOSE4_PS(r, u, t, v);
因为这是一个就地转置,并且4个输入向量也用于输出。
【讨论】:
谢谢,这解决了它。为什么它让我在 MSVC 中而不是在 GCC 中这样做? 两个编译器的_MM_TRANSPOSE4_PS
的定义是否相同?
它是直接使用内在函数。 GCC 将_mm_unpacklo_ps
定义为调用__builtin_ia32_unpackps
的内联函数。如果它在这个宏中使用了_mm_unpacklo_ps
,你的代码也会因为同样的原因而失败。
@RossRidge,是的,我现在明白了。问题出在 MSVC 中。它编译并运行_mm_setr_ps(0.0f, 0.0f, 0.0f, 1.0f) = _mm_shuffle_ps(tmp2,tmp3, 0XDD);
就好了。
@PaulR,我的第一个答案真的很糟糕,我很惊讶我没有被否决。但无论如何,我用 MSVC 的程序集输出更新了我的答案。我不确定它在做什么,但它显然没有将结果存储在行中。【参考方案2】:
MSVC 使用自己的定义:
#define _MM_TRANSPOSE4_PS(row0, row1, row2, row3) \
__m128 tmp3, tmp2, tmp1, tmp0; \
\
tmp0 = _mm_shuffle_ps((row0), (row1), 0x44); \
tmp2 = _mm_shuffle_ps((row0), (row1), 0xEE); \
tmp1 = _mm_shuffle_ps((row2), (row3), 0x44); \
tmp3 = _mm_shuffle_ps((row2), (row3), 0xEE); \
\
(row0) = _mm_shuffle_ps(tmp0, tmp1, 0x88); \
(row1) = _mm_shuffle_ps(tmp0, tmp1, 0xDD); \
(row2) = _mm_shuffle_ps(tmp2, tmp3, 0x88); \
(row3) = _mm_shuffle_ps(tmp2, tmp3, 0xDD); \
最后一行被转换为_mm_setr_ps(0.0f, 0.0f, 0.0f, 1.0f) = _mm_shuffle_ps(tmp2,tmp3, 0XDD);
,它在 MSVC 中编译得很好,但在 GCC 中由于左值错误而失败。我不确定为什么 MSVC 允许这样做。
我在 MSVC2013 中查看了这段代码的汇编输出
#include <immintrin.h>
#include <stdio.h>
int main()
__m128 rows[4];
//rows[0] = _mm_setr_ps( 1, 2, 3, 4);
//rows[1] = _mm_setr_ps( 5, 6, 7, 8);
rows[2] = _mm_setr_ps( 9,10,11,12);
rows[3] = _mm_setr_ps(13,14,15,16);
//_MM_TRANSPOSE4_PS(rows[0],rows[1],rows[2],rows[3]);
//_MM_TRANSPOSE4_PS(rows[0],rows[1],rows[2],_mm_setr_ps(0.0f, 0.0f, 0.0f, 1.0f));
rows[2] = _mm_shuffle_ps(rows[2], rows[3], 0x88);
_mm_setr_ps(0.0f, 0.0f, 0.0f, 1.0f) = _mm_shuffle_ps(rows[2],rows[3], 0XDD);
这里是相关的汇编代码
; Line 14
mov eax, 16
imul rax, 3
mov ecx, 16
imul rcx, 2
movups xmm0, XMMWORD PTR rows$[rsp+rcx]
shufps xmm0, XMMWORD PTR rows$[rsp+rax], 136 ; 00000088H
movaps XMMWORD PTR $T6[rsp], xmm0
mov eax, 16
imul rax, 2
movaps xmm0, XMMWORD PTR $T6[rsp]
movups XMMWORD PTR rows$[rsp+rax], xmm0
; Line 15
mov eax, 16
imul rax, 3
mov ecx, 16
imul rcx, 2
movups xmm0, XMMWORD PTR rows$[rsp+rcx]
shufps xmm0, XMMWORD PTR rows$[rsp+rax], 221 ; 000000ddH
movaps XMMWORD PTR $T8[rsp], xmm0
movaps xmm0, XMMWORD PTR __xmm@3f800000000000000000000000000000
movaps XMMWORD PTR $T7[rsp], xmm0
movaps xmm0, XMMWORD PTR $T8[rsp]
movaps XMMWORD PTR $T7[rsp], xmm0
【讨论】:
我仍然不清楚如何将row3
参数设置为_mm_setr_ps(...)
,因为它是在宏的最后一行分配的?
@PaulR,好点子。但即使它给出了错误的结果(_mm_setr_ps(0.0f, 0.0f, 0.0f, 1.0f) = _mm_shuffle_ps(tmp2,tmp3, 0XDD)
),它仍然应该编译。但我仍然想知道为什么 GCC 使用映射到内在函数而不是直接映射到内在函数的内置函数。我想一个原因是防止这种错误发生?
否 - 我认为 gcc 完全正确地使用 error: lvalue required as left operand of assignment
保释 - _mm_setr_ps(...)
不是左值,尝试分配给它确实是一个错误 - 我不知道这是如何过去的MSVC - 也许 MS 定义 _mm_setr_ps
的方式有些有趣?
@PaulR,再次正确。我没想到他不够细心。无论如何,这就是 _mm_setr_ps(0.0f, 0.0f, 0.0f, 1.0f) = _mm_shuffle_ps(tmp2,tmp3, 0XDD);
在 MSVC 中编译良好但在 GCC 中给出 lvalue
错误的线索。我明天再调查一下。我不知道为什么我不再关心 MSVC...以上是关于_MM_TRANSPOSE4_PS 导致 GCC 中的编译器错误?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 gcc 将 _mm256_permute2f128_ps 编译为 Vinsertf128 指令?
C 内在函数、SSE2 点积和 gcc -O3 生成的程序集