[英]sse C++ memory commands
SSE組件具有SQRTPS命令。
SQRTPS命令具有2個版本:
SQRTPS xmm1, xmm2
SQRTPS xmm1, m128
gcc / clang / vs(所有)編譯器具有輔助函數_mm_sqrt_ps
。
但是_mm_sqrt_ps
僅適用於預加載的xmm(使用_mm_set_ps / _mm_load_ps)。
例如,從Visual Studio: http : //msdn.microsoft.com/zh-cn/library/vstudio/8z67bwwk%28v=vs.100%29.aspx
我的期望:
__attribute__((aligned(16))) float data[4];
__attribute__((aligned(16))) float result[4];
asm{
sqrtps xmm0, data // DIRECTLY FROM MEMORY
movaps result, xmm0
}
我所擁有的(C語言):
__attribute__((aligned(16))) float data[4];
__attribute__((aligned(16))) float result[4];
auto xmm = _mm_load_ps(&data) // or _mm_set_ps
xmm = _mm_sqrt_ps(xmm);
_mm_store_ps(&result[0], xmm);
(在asm中):
movaps xmm1, data
sqrtps xmm0, xmm1 // FROM REGISTER
movaps result, xmm0
換句話說,我想看到這樣的東西:
__attribute__((aligned(16))) float data[4];
__attribute__((aligned(16))) float result[4];
auto xmm = _mm_sqrt_ps(data); // DIRECTLY FROM MEMORY, no need to load (because there is such instruction)
_mm_store_ps(&result[0], xmm);
快速研究:我制作了以下文件,名為mysqrt.cpp
:
#include <pmmintrin.h>
extern "C" __m128 MySqrt(__m128* a) {
return _mm_sqrt_ps(a[1]);
}
嘗試gcc,即g++4.8 -msse3 -O3 -S mysqrt.cpp && cat mysqrt.s
:
_MySqrt:
LFB526:
sqrtps 16(%rdi), %xmm0
ret
clang++3.6 -msse3 -O3 -S mysqrt.cpp && cat mysqrt.s
( clang++3.6 -msse3 -O3 -S mysqrt.cpp && cat mysqrt.s
):
_MySqrt: ## @MySqrt
.cfi_startproc
## BB#0: ## %entry
pushq %rbp
Ltmp0:
.cfi_def_cfa_offset 16
Ltmp1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp2:
.cfi_def_cfa_register %rbp
sqrtps 16(%rdi), %xmm0
popq %rbp
retq
不了解VS,但如果需要的話,至少gcc和clang似乎都可以生成sqrtps
內存版本。
UPDATE函數用法示例:
#include <iostream>
#include <pmmintrin.h>
extern "C" __m128 MySqrt(__m128* a);
int main() {
__m128 x[2];
x[1] = _mm_set_ps1(4);
__m128 y = MySqrt(x);
std::cout << y[0] << std::endl;
}
// output:
2
更新2:關於您的代碼,您應該這樣做:
auto xmm = _mm_sqrt_ps(*reinterpret_cast<__m128*>(data));
當然,這需要您自擔風險,您應保證data
包含有效的__m128
並正確對齊。
我認為您誤解了原始_mm_sqrt_ps(__m128)
提供的接口。 這里的參數類型可以是保存在存儲器或寄存器中的變量。 擴展類型__m128
行為類似於任何常規的內置類型,例如double
,並且未綁定到xmm寄存器,但也可以存儲在內存中。
編輯除非您使用asm
,否則編譯器將確定是否以及何時將變量加載到寄存器中或保留在內存中。 因此,在以下代碼段中
__m128 foo(const __m128 x, const __m128*y, std::size_t n)
{
__m128 result = _mm_set_ps(1.0);
while(n--)
result = _mm_mul_ps(result,_mm_add_ps(x,_mm_sqrt_ps(*y++)));
return result;
}
哪些變量存儲在寄存器中由編譯器決定。 我認為編譯器會將x
和result
放入xmm寄存器,但直接從內存獲取*y
。
您的問題的答案是,您至少無法使用內部函數來控制this,至少對於對齊的負載而言。 由編譯器決定是否使用SQRTPS xmm1,xmm2或SQRTPS xmm1,m128。 如果要100%確定,則必須以匯編形式編寫。 我認為,這是內在函數的不足之一(至少在當前已實現)。
一些代碼可以幫助解釋這一點。
我們可以得到GCC(帶有-O3的64位)來使用對齊和不對齊的負載生成兩個版本
float x[4], y[4]
__m128 x4 = _mm_loadu_ps(x);
__m128 y4 = _mm_sqrt_ps(x4);
_mm_storeu_ps(y,y4);
這給出了(使用Intel語法)
movups xmm0, XMMWORD PTR [rdx]
sqrtps xmm0, xmm0
但是,如果我們進行對齊的荷載,則會得到另一種形式
float x[4], y[4]
__m128 x4 = _mm_load_ps(x);
__m128 y4 = _mm_sqrt_ps(x4);
_mm_storeu_ps(y,y4);
這將載荷和平方根組合成一條指令
sqrtps xmm0, XMMWORD PTR [rax]
大多數人會說“信任編譯器”。 我不同意。 如果使用內在函數,則應假定您知道自己在做什么,而不是編譯器。 這是msvc和gcc在高度優化的矩陣multp之間的性能差異示例,其中GCC選擇了一種形式,而MSVC選擇了另一種形式(用於乘法而不是sqrt),性能差異。
因此,再次重申,如果您使用對齊的負載,則只能祈禱編譯器可以執行所需的操作。 然后也許在下一版的編譯器中它做了一些不同的工作...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.