我正在尝试使用 XMM 寄存器使用 SSE2 指令在汇编语言中将 4 个数字添加到其他 4 个数字中。我确实成功了,但我遇到了一些我不明白的事情。如果我以这种方式添加:
movdqu xmm0, oword [var1]
movdqu xmm1, oword [var2]
paddd xmm0, xmm1
movdqu oword [var1], xmm0
Run Code Online (Sandbox Code Playgroud)
它工作得很好。
但如果我这样尝试:
movdqu xmm0, oword [var1]
paddd xmm0, oword [var2]
movdqu oword [var1], xmm0
Run Code Online (Sandbox Code Playgroud)
它给了我一个分段错误。
第二种方法有什么问题?我正在使用 Nasm、Intel Atom N270、Linux Mint 12 32 位
我正在学习如何在视频应用程序中使用英特尔 MMX 和 SSE 指令。我有一个 8 字节的字,我想将所有 8 个字节相加并产生一个整数作为结果。直接的方法是连续 7 次移动和添加,但这很慢。这样做的最快方法是什么?是否有针对此的 MMX 或 SSE 指令?
这是这样做的缓慢方法
unsigned long PackedWord = whatever....
int byte1 = 0xff & (PackedWord);
int byte2 = 0xff & (PackedWord >> 8);
int byte3 = 0xff & (PackedWord >> 16);
int byte4 = 0xff & (PackedWord >> 24);
int byte5 = 0xff & (PackedWord >> 32);
int byte6 = 0xff & (PackedWord >> 40);
int byte7 = 0xff & (PackedWord >> 48);
int byte8 = 0xff & …Run Code Online (Sandbox Code Playgroud) 我只是想检查优化一些基本例程的最佳方法。在这种情况下,我尝试了将 2 个浮点向量相乘的非常简单的示例:
void Mul(float *src1, float *src2, float *dst)
{
for (int i=0; i<cnt; i++) dst[i] = src1[i] * src2[i];
};
Run Code Online (Sandbox Code Playgroud)
普通的 C 实现非常慢。我使用 AVX 做了一些外部 ASM,也尝试使用内在函数。这些是测试结果(时间越小越好):
ASM: 0.110
IPP: 0.125
Intrinsics: 0.18
Plain C++: 4.0
Run Code Online (Sandbox Code Playgroud)
(使用 MSVC 2013、SSE2 编译,尝试过 Intel 编译器,结果几乎相同)
正如您所看到的,我的 ASM 代码甚至击败了 Intel Performance Primitives(可能是因为我做了很多分支以确保我可以使用 AVX 对齐指令)。但我个人更喜欢使用内在方法,它更易于管理,我认为编译器应该在优化所有分支和内容方面做得最好(我的 ASM 代码在这方面很糟糕,但速度更快)。所以这是使用内在函数的代码:
int i;
for (i=0; (MINTEGER)(dst + i) % 32 != 0 && i < cnt; i++) dst[i] = src1[i] * src2[i];
if ((MINTEGER)(src1 + i) % 32 …Run Code Online (Sandbox Code Playgroud) 我想使用 SSE 内在函数翻译此代码。
for (uint32_t i = 0; i < length; i += 4, src += 4, dest += 4)
{
uint32_t value = *(uint32_t*)src;
*(uint32_t*)dest = ((value >> 16) & 0xFFFF) | (value << 16);
}
Run Code Online (Sandbox Code Playgroud)
有没有人知道执行 16 位字交换的内在因素?
很高兴 gcc 编译器 4.8 带有带有 -Ofast 选项的 AVX 优化。但是,我发现了一个有趣但愚蠢的错误,它增加了不必要的额外计算。也许我错了,所以有人可以给我一个解释吗?
原来的C++源代码如下:
#define N 1000007
float a[N],b[N],c[N],d[N],e[N];
int main(int argc, char *argv[]){
cout << a << ' ' << b << ' ' << c << endl;
for(int x=0; x<N; ++x){
c[x] = 1/sqrt((a[x]+b[x]-c[x])*d[x]/e[x]);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
代码在 Ubuntu 14.04.3 x86_64 中使用 g++ 4.8.4 编译: g++ -mavx avx.cpp -masm=intel -c -g -Wa,-ahl=avx.asm -Ofast
汇编源代码如下:
90 .LVL10:
91 006b C5FC2825 vmovaps ymm4, YMMWORD PTR .LC0[rip]
91 00000000
92 0073 31C0 xor eax, …Run Code Online (Sandbox Code Playgroud) 我对 MOVSD 汇编指令有些困惑。我写了一些计算矩阵乘法的数字代码,只是使用没有 SSE 内在函数的普通 C 代码。我什至不包括用于编译的 SSE2 内在函数的头文件。但是当我检查汇编器输出时,我看到:
1)使用128位向量寄存器XMM;2) 调用SSE2 指令MOVSD。
我知道 MOVSD 本质上是在单双精度浮点上运行的。它只使用 XMM 寄存器的低 64 位并将高 64 位设置为 0。但我只是不明白两件事:
1) 我从来没有给编译器任何使用 SSE2 的提示。另外,我使用的是 GCC 而不是英特尔编译器。据我所知,intel 编译器会自动寻找向量化的机会,但 GCC 不会。那么 GCC 怎么知道使用 MOVSD 的呢??或者,这个 x86 指令早在 SSE 指令集之前就已经存在了,而 SSE2 中的 _mm_load_sd() 内在函数只是为使用 XMM 寄存器进行标量计算提供向后兼容性?
2)为什么编译器不使用其他浮点寄存器,要么是80位浮点栈,要么是64位浮点寄存器??为什么必须使用 XMM 寄存器(通过设置高位 64 位 0 并实质上浪费该存储)?XMM 是否提供更快的访问?
顺便说一下,我还有一个关于 SSE2 的问题。我只是看不出 _mm_store_sd() 和 _mm_storel_sd() 之间的区别。两者都将较低的 64 位值存储到一个地址。有什么不同?性能差异??对齐方式不同??
谢谢你。
更新 1:
OKAY,很明显,当我第一次问这个问题时,我缺乏关于 CPU 如何管理浮点运算的一些基本知识。所以专家们往往认为我的问题是无稽之谈。由于我什至没有包含最短的示例 C 代码,因此人们可能也会认为这个问题含糊不清。在这里,我将提供一个评论作为答案,希望对任何不清楚现代 CPU 上的浮点运算的人有用。
我正在阅读 Apress 的现代 x86 汇编语言书籍。对于编程 64 位 SSE 示例,作者将align 16放在代码中的特定点上。例如
.code
ImageUint8ToFloat_ proc frame
_CreateFrame U2F_,0,64 ; helper macros to create prolog
_SaveXmmRegs xmm10,xmm11,xmm12,xmm13 ; helper macros to create prolog
_EndProlog ; helper macros to create prolog
...
shrd r8d,
pxor xmm5,xmm5
align 16 ; Why this is here ?
@@:
movdqa xmm0,xmmword ptr [rdx]
movdqa xmm10,xmmword ptr [rdx+16]
movdqa xmm2,xmm0
punpcklbw xmm0,xmm5
punpckhbw xmm2,xmm5
movdqa xmm1,xmm0
movdqa xmm3,xmm2
...
Run Code Online (Sandbox Code Playgroud)
作者解释说有必要放置align 16,因为我们使用的是 SSE,以便指令本身对齐。没关系。我的问题是为什么作者选择将align 16放在该特定位置。作为程序员,我应该如何决定 …
我有一个功能可以将 8 位图像缩小两倍。我之前已经用 SSE 优化了 rgb32 案例。现在我想对 gray8 案例做同样的事情。
在核心,有一个函数取两行像素数据,其工作方式如下:
/**
* Calculates the average of two rows of gray8 pixels by averaging four pixels.
*/
void average2Rows(const uint8_t* row1, const uint8_t* row2, uint8_t* dst, int size)
{
for (int i = 0; i < size - 1; i += 2)
*(dst++) = ((row1[i]+row1[i+1]+row2[i]+row2[i+1])/4)&0xFF;
}
Run Code Online (Sandbox Code Playgroud)
现在,我想出了一个 SSE 变体,它大约快三倍,但它确实涉及很多改组,我认为可能会做得更好。有人看到这里可以优化什么吗?
/* row1: 16 8-bit values A-P
* row2: 16 8-bit values a-p
* returns 16 8-bit values (A+B+a+b)/4, (C+D+c+d)/4, ..., …Run Code Online (Sandbox Code Playgroud) __m128i以这种方式定义变量时:
__m128i a;
a.m128i_i32[0] = 65000;
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
错误:请求'a'中的成员'm128i_i32',它是非类类型'__m128i {aka __vector(2) long long int}' a.m128i_i32[0] = 65000;
我已经包含了以下头文件:
#include <x86intrin.h>
#include <emmintrin.h>
#include <smmintrin.h>
Run Code Online (Sandbox Code Playgroud) 我已经用 SSSE3 完成了这个,现在我想知道这是否可以用 AVX2 完成以获得更好的性能?
我用一个零字节填充 24 位 rgb,使用来自Fast 24-bit array -> 32-bit array conversion 的代码?.
static const __m128i mask = _mm_setr_epi8(0, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8, -1, 9, 10, 11, -1);
for (size_t row = 0; row < height; ++row)
{
for (size_t column = 0; column < width; column += 16)
{
const __m128i *src = reinterpret_cast<const __m128i *>(in + row * in_pitch + column + (column << 1));
__m128i *dst …Run Code Online (Sandbox Code Playgroud)