- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想确保gcc知道:
template<typename T, typename T2>
void f(const T* __restrict__ __attribute__((aligned(32))) x,
T2* __restrict__ __attribute__((aligned(32))) out) {}
int square(const float* __restrict__ __attribute__((aligned(32))) x,
const int size,
float* __restrict__ __attribute__((aligned(32))) out0,
float* __restrict__ __attribute__((aligned(32))) out1,
float* __restrict__ __attribute__((aligned(32))) out2,
float* __restrict__ __attribute__((aligned(32))) out3,
float* __restrict__ __attribute__((aligned(32))) out4) {
for (int i = 0; i < size; ++i) {
out0[i] = x[i];
out1[i] = x[i] * x[i];
out2[i] = x[i] * x[i] * x[i];
out3[i] = x[i] * x[i] * x[i] * x[i];
out4[i] = x[i] * x[i] * x[i] * x[i] * x[i];
}
}
.L3:
vmovups ymm1, YMMWORD PTR [rbx+rax]
vmulps ymm0, ymm1, ymm1
vmovups YMMWORD PTR [r14+rax], ymm0
vmulps ymm0, ymm1, ymm0
vmovups YMMWORD PTR [r15+rax], ymm0
vmulps ymm0, ymm1, ymm0
vmovups YMMWORD PTR [r12+rax], ymm0
vmulps ymm0, ymm1, ymm0
vmovups YMMWORD PTR [rbp+0+rax], ymm0
add rax, 32
cmp rax, rdx
jne .L3
and r13d, -8
vzeroupper
.L3:
vmovups xmm2, XMMWORD PTR [rbx+rax]
vinsertf128 ymm1, ymm2, XMMWORD PTR [rbx+16+rax], 0x1
vmulps ymm0, ymm1, ymm1
vmovups XMMWORD PTR [r14+rax], xmm0
vextractf128 XMMWORD PTR [r14+16+rax], ymm0, 0x1
vmulps ymm0, ymm1, ymm0
vmovups XMMWORD PTR [r13+0+rax], xmm0
vextractf128 XMMWORD PTR [r13+16+rax], ymm0, 0x1
vmulps ymm0, ymm1, ymm0
vmovups XMMWORD PTR [r12+rax], xmm0
vextractf128 XMMWORD PTR [r12+16+rax], ymm0, 0x1
vmulps ymm0, ymm1, ymm0
vmovups XMMWORD PTR [rbp+0+rax], xmm0
vextractf128 XMMWORD PTR [rbp+16+rax], ymm0, 0x1
add rax, 32
cmp rax, rdx
jne .L3
and r15d, -8
vzeroupper
最佳答案
不,使用float *__attribute__((aligned(32))) x
意味着指针本身存储在对齐的内存中,而不是指向对齐的内存。1
有一种方法可以执行此操作,但是它仅对gcc有用,对clang或ICC无效。
有关适用于所有GNU C兼容编译器的__builtin_assume_aligned
,请参见How to tell GCC that a pointer argument is always double-word-aligned?;有关适用于GCC的__attribute__((aligned(32)))
的更多详细信息,请参见How can I apply __attribute__(( aligned(32))) to an int *?。
我使用__restrict
而不是__restrict__
,因为C99 restrict
的C++扩展名可移植到所有主流x86 C++编译器(包括MSVC)中。
typedef float aligned32_float __attribute__((aligned(32)));
void prod(const aligned32_float * __restrict x,
const aligned32_float * __restrict y,
int size,
aligned32_float* __restrict out0)
{
size &= -16ULL;
#if 0 // this works for clang, ICC, and GCC
x = (const float*)__builtin_assume_aligned(x, 32); // have to cast the result in C++
y = (const float*)__builtin_assume_aligned(y, 32);
out0 = (float*)__builtin_assume_aligned(out0, 32);
#endif
for (int i = 0; i < size; ++i) {
out0[i] = x[i] * y[i]; // auto-vectorized with a memory operand for mulps
// note clang using two separate movups loads
// instead of a memory operand for mulps
}
}
movaps
/
vmovaps
代替
ups
。 (与MSVC和ICC不同,它们从不使用
movaps
进行加载/存储,对于在Core2 / K10或更旧版本上运行的任何内容都缺少优化)。正如您所注意到的,它是将
-mavx256-split-unaligned-load
/
store
效果应用于除Haswell(
Why doesn't gcc resolve _mm256_loadu_pd as single vmovupd?)。之外的其他调音,这是您的语法无效的另一个线索。
vmovups
时不会出现性能问题;当地址在运行时对齐时,它在所有支持AVX的CPU上的性能与
vmovaps
相同。因此,在实践中,您的
-march=haswell
输出没有真正的问题。只有Nehalem和Bulldozer之前的较旧的CPU始终将
movups
解码为多个uops。
mulps
的内存操作数中。
out0[i] = x[i] * y[i]
,其中加载结果仅需要一次。 或
out0[i] *= x[i]
。知道对齐方式后,就可以启用
movaps
/
mulps xmm0, [rsi]
,否则为2x
movups
+
mulps
。您甚至可以在ICC或MSVC之类的编译器上检查此优化,即使它们知道有对齐保证也使用
movups
,但是当他们可以将负载折叠到ALU操作中时,仍会生成需要对齐的代码。
__builtin_assume_aligned
是执行的唯一真正可移植的方式(对于GNU C编译器)。您可以像将指针传递给
struct aligned_floats { alignas(32) float f[8]; };
一样进行破解,但这使用起来很麻烦,并且除非您实际上通过该类型的对象访问内存,否则编译器将无法假定对齐。 (例如,将指向该指针的指针转换回
float *
I try to use one read and lots of write to saturate the cpu ports for writing.
c[i] = a[i]+b[i]
或STREAM triad这样的2倍负载+ 1倍存储内存访问模式将最接近
maxing out total L1d cache load+store bandwidth。在SnB / IvB上,每个加载/存储256位 vector 需要2个周期,因此在加载的第二个周期内,存储地址oups需要时间在端口2或3上使用AGU。在Haswell及更高版本(256位宽的加载/存储端口)上,存储需要使用非索引寻址模式,以便它们可以在端口7上使用简单寻址模式存储AGU。
and rsp,-32
,因为它假定RSP已对齐。 (它实际上并没有溢出任何YMM规则,因此无论如何它都应该对此进行了优化,但是gcc在使用局部对齐或自动矢量化创建的对象时已经存在此错过优化的错误一段时间了。)
<source>:4:6: note: The ABI for passing parameters with 32-byte alignment has changed in GCC 4.6
关于c++ - 结合__restrict__和__attribute __((aligned(32))),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54189780/
这个使用两个 __restrict__ int 数组的内核编译得很好: __global__ void kerFoo( int* __restrict__ arr0, int* __restrict_
我不太明白 __restrict__ 的概念CUDA 中的标记。 我用 __restrict__ 读过避免指针别名,特别是,如果指向的变量是只读的,则变量的读取得到优化,因为它被缓存了。 这是代码的简
我一直在看Mike Acton's talk on Data-oriented design in C++在 CppCon 2014 中,他给出了这个例子: int Foo::Bar(int coun
我刚刚测试了一个小例子来检查 __restrict__ 是否在最新编译器的 C++ 中工作: void foo(int x,int* __restrict__ ptr1, int& v2) {
这是一些相当简单的代码,使用 -O2 (gcc 4.8.5) 编译: unsigned char * linebuf; int yuyv_tojpegycbcr(unsigned char * bu
因为我的指针都指向非重叠内存,所以我全力以赴将传递给内核(及其内联函数)的指针替换为限制,并使它们也成为常量,只要有可能。然而,这增加了一些内核的寄存器使用,而减少了其他内核的使用。这对我来说没有多大
智能指针是下面的指针,那么有什么方法可以定义函数的 shared_ptr 参数而不是另一个 shared_ptr 或任何类型的另一个指针的别名? 或者出于某种原因,这是不必要的吗? 我关心 gcc >
我看到了一些关于它的帖子,但仍然不知道如何修复该错误。事情是这样的: char *data; char chat; snprintf(chat,"%d",getc(file)
这是我写的一些代码(使用 GCC 的 __restrict__ 扩展到 C++): #include using namespace std; int main(void) { int i
假设我有 struct s { int* __restrict__ p1; double v; }; void foo(int* __restrict__ p2, struct s m
char *local_buffer, *buff; fgets(buff, 1024, fp); local_buffer=strtok(buff,'\t'); //Error is coming
我是一名优秀的程序员,十分优秀!