防止gcc破坏我的AVX2内部函数

问题描述 投票:2回答:1

请考虑以下循环:

template <typename T>
void copytail(T* __restrict__ dest, const T* __restrict__ src, size_t count) {
  constexpr size_t chunk_size = 4 * 32;
  size_t byte_count = sizeof(T) * count;
  size_t chunks = byte_count / chunk_size;
  auto rest = byte_count - byte_count / chunk_size * chunk_size;
  auto rest_vecs = (rest + 31) / 32;
  __m256i* dest256 = (__m256i*)((char *)dest + byte_count - rest_vecs * 32);
  __m256i* src256  = (__m256i*)((char *)src  + byte_count - rest_vecs * 32);
  for (size_t j = 0; j < rest_vecs; j++) {
      _mm256_storeu_si256(dest256 + j, _mm256_loadu_si256(src256 + j));
  }
}


void tail_copy(char* d, const char* s, size_t overshoot) {
    copytail(d, s, overshoot);
}

不要太在意它的功能,因为它是基于更完整功能的简化测试用例-但基本上,它从srcdest最多复制4个AVX2向量,并与结束的区域。

由于任何原因1-O3处的gcc 8.1都会生成此奇数汇编:

tail_copy(char*, char const*, unsigned long):
  mov rax, rdx
  and eax, 127
  add rax, 31
  mov rcx, rax
  and rcx, -32
  sub rdx, rcx
  shr rax, 5
  je .L30
  sal rax, 5
  mov r8d, eax
  add rdi, rdx
  add rsi, rdx
  test dil, 1
  jne .L32
.L3:
  test dil, 2
  jne .L33
.L4:
  test dil, 4
  jne .L34
.L5:
  mov ecx, r8d
  shr ecx, 3
  rep movsq   # oh please no
  xor eax, eax
  test r8b, 4
  jne .L35
  test r8b, 2
  jne .L36
  # many more tail-handling cases follow

基本上是一次rep movsq循环,一次复制8个字节,然后是一堆用于处理奇数字节的尾部处理代码(大多数未显示,可以在godbolt上看到完整的汇编)。

因此,我希望gcc或多或少以书面形式发出我的复制循环-至少32字节的AVX2加载和存储应出现在源代码中。重要的是,我希望它在此函数中是局部的:也就是说,不要更改编译器参数。


[1可能是memcpy识别,然后是memcpy内联。

c++ gcc compiler-optimization intrinsics avx2
1个回答
0
投票

您对memcpy识别的假设似乎是正确的(__builtin_memcpy首次出现在ldist遍中,如在-fdump-tree-all日志中可以看到,这阻碍了优化:

__attribute__ ((optimize ("no-tree-loop-distribute-patterns")))
void tail_copy(char* d, const char* s, size_t overshoot) {
    copytail(d, s, overshoot);
}

将其应用于模板定义似乎也可行。

[如果CPU支持ERMS(就像大多数具有AVX2的Intel CPU一样),则尚不清楚这是否有所改进。

© www.soinside.com 2019 - 2024. All rights reserved.