【问题标题】:vectorization fails with GCCGCC 导致矢量化失败
【发布时间】:2014-05-05 20:19:15
【问题描述】:

我试图理解矢量化,但令我惊讶的是,这个非常简单的代码没有被矢量化

#define n 1024
int main () {
  int i, a[n], b[n], c[n];

  for(i=0; i<n; i++) { a[i] = i; b[i] = i*i; }
  for(i=0; i<n; i++) c[i] = a[i]+b[i];
}

虽然英特尔编译器出于某种原因对初始化循环进行矢量化,但第 5 行。

> icc -vec-report a.c
a.c(5): (col. 3) remark: LOOP WAS VECTORIZED

使用 GCC,我似乎一无所获

> gcc -ftree-vectorize -ftree-vectorizer-verbose=2 a.c

我做错了吗?这不应该是一个非常简单的矢量化循环吗?所有相同的操作,连续内存等。我的 CPU 支持 SSE1/2/3/4。

--- 更新 ---

按照下面的答案,这个例子对我有用。

#include <stdio.h>
#define n 1024

int main () {
  int i, a[n], b[n], c[n];

  for(i=0; i<n; i++) { a[i] = i; b[i] = i*i; }
  for(i=0; i<n; i++) c[i] = a[i]+b[i];

  printf("%d\n", c[1023]);  
}

用icc

> icc -vec-report a.c
a.c(7): (col. 3) remark: LOOP WAS VECTORIZED
a.c(8): (col. 3) remark: LOOP WAS VECTORIZED

和 gcc

> gcc -ftree-vectorize -fopt-info-vec -O a.c
a.c:8:3: note: loop vectorized
a.c:7:3: note: loop vectorized

【问题讨论】:

  • 或者 GCC 可能只是将其全部删除。
  • 使用 gcc 的 -O3 选项来获取更多信息。
  • 您应该从程序外部传入n,以确保优化器不只是计算最终结果并删除循环。

标签: c++ c gcc vectorization icc


【解决方案1】:

我稍微修改了您的源代码以确保 GCC 无法删除循环:

#include <stdio.h>
#define n 1024

int main () {
  int i, a[n], b[n], c[n];

  for(i=0; i<n; i++) { a[i] = i; b[i] = i*i; }
  for(i=0; i<n; i++) c[i] = a[i]+b[i];

  printf("%d\n", c[1023]);  
}

GCC (v4.8.2) 可以向量化这两个循环,但它需要 -O 标志:

gcc -ftree-vectorize -ftree-vectorizer-verbose=1 -O2 a.c

我得到:

在 a.c:8 处分析循环

在 a.c:8 处矢量化循环

a.c:8 注意:循环矢量化。在 a.c:7 处分析循环

在 a.c:7 处矢量化循环

a.c:7 注意:循环矢量化。 a.c:注意:矢量化 2 个循环 功能。

使用-fdump-tree-vect 开关 GCC 将在a.c.##t.vect 文件中转储更多信息(了解“内部”发生的事情非常有用)。

还要考虑:

【讨论】:

  • 看起来很神奇,但确实有效。我必须(首先)添加 printf,我想这样编译器就不会认为它是一个无用的变量。然后我将 -O 和 -fopt-info-vec 添加到编译器选项中。我的编译器 (GCC 4.9.0) 没有显示任何带有 -ftree-vectorizer-verbose= 的内容。如果用手册页中的所有选项替换 -O,它什么也不做!
  • 请注意,编译器仍然可以删除您的循环,因为它可以在编译期间运行循环,替换结果。
【解决方案2】:

大多数情况下,-Ofast -march=native 选项会将您的代码矢量化(如果它可以在您的处理器上)。

$ gcc compute_simple.c -Ofast -march=native -fopt-info-vec -o compute_simple.bin
compute_simple.c:14:5: note: loop vectorized
compute_simple.c:14:5: note: loop versioned for vectorization because of possible aliasing
compute_simple.c:14:5: note: loop vectorized

要了解您的处理器是否可以做到这一点,请使用 lscpu 并查看可用标志。

$ lscpu
Architecture:        x86_64
CPU op-mode(s):      32-bit, 64-bit
Byte Order:          Little Endian
CPU(s):              12
...
Vendor ID:           GenuineIntel
...
Flags:               fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge  
 mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall   
nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl   
xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64   
monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1   
sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand   
lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ibpb   
stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1   
hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt   
xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify   
hwp_act_window hwp_epp md_clear flush_l1d

您需要在 Intel 上使用 sse/avx,在 ARM 上需要 neon,在 AMD 上需要其他(如 xop)。

您可以通过搜索gcc 文档找到更多关于矢量化的信息。

这是一篇关于该主题的好文章,其中包含可用于许多平台的标志: https://gcc.gnu.org/projects/tree-ssa/vectorization.html

最后,如上所述,在旧版本的 gcc 中使用-ftree-vectorizer-verbose=n,在最近的版本中使用-fopt-info-vec/-fopt-info-vec-missed,看看什么是矢量化的。

【讨论】:

    猜你喜欢
    • 2019-03-27
    • 2011-04-20
    • 1970-01-01
    • 1970-01-01
    • 2014-07-19
    • 2018-12-16
    • 1970-01-01
    • 2017-05-03
    • 1970-01-01
    相关资源
    最近更新 更多