c++ - 为什么 'simplified' 代码没有向量化

标签 c++ gcc rust clang vectorization

我实现了以下代码,将 32 个字节的输入转换为大写:
版本 1:

void to_upper(char* input) {
    for (int i = 0; i < 32; ++i) { 
        input[i] = (input[i] >= 'a' && input[i] <= 'z') ? input[i] - 32 : input[i]; 
    }
}
版本 2:
void to_upper(char* input) {
    for (int i = 0; i < 32; ++i) { 
        if (input[i] >= 'a' && input[i] <= 'z') {
            input[i] = input[i] - 32; // same for: input[i] -= 32;
        }
    }
}
第一个版本被自动矢量化,第二个没有。该行为在 clang 和 gcc 中是一致的。此外,我也在 Rust 中实现了这两个版本,并且 Rust 编译器执行相同的操作,版本 1 自动矢量化,版本 2 不是。
是什么限制了编译器矢量化第二个版本?

最佳答案

基本上优化传递更难识别第二个循环中的条件分配。
在第一种情况下,GCC 生成一个稍微不同的中间表示,它允许 if-conversion pass 将代码转换为可向量化的形式:

  <bb 3>:
  # i_18 = PHI <i_14(4), 0(2)>
  # ivtmp_24 = PHI <ivtmp_21(4), 32(2)>
  _6 = (sizetype) i_18;
  _7 = input_5(D) + _6;
  _8 = *_7;
  _9 = (unsigned char) _8;
  _10 = _9 + 159;
  _11 = _9 + 224;
  iftmp.0_12 = (char) _11;
  iftmp.0_2 = _10 <= 25 ? iftmp.0_12 : _8;
  *_7 = iftmp.0_2;
  i_14 = i_18 + 1;
  ivtmp_21 = ivtmp_24 - 1;
  if (ivtmp_21 != 0)
    goto <bb 4>;
  else
    goto <bb 5>;
而在第二种情况下,代码包含使分析复杂化和中断矢量化的虚假跳转:
  <bb 3>:
  # i_15 = PHI <i_14(6), 0(2)>
  # ivtmp_26 = PHI <ivtmp_25(6), 32(2)>
  _5 = (sizetype) i_15;
  _7 = input_6(D) + _5;
  _8 = *_7;
  _9 = (unsigned char) _8;
  _10 = _9 + 159;
  if (_10 <= 25)
    goto <bb 4>;
  else
    goto <bb 5>;

  <bb 4>:
  _11 = _9 + 224;
  _12 = (char) _11;
  *_7 = _12;

  <bb 5>:
  i_14 = i_15 + 1;
  ivtmp_25 = ivtmp_26 - 1;
  if (ivtmp_25 != 0)
    goto <bb 6>;
  else
    goto <bb 7>;
许多优化 channel 作为模式匹配器工作,可以识别和优化常见情况,因此我不会对这种行为感到惊讶。
您可以尝试在 GCC tracker 中提交错误.

关于c++ - 为什么 'simplified' 代码没有向量化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63004404/

相关文章:

C++检测是否存在按名称接受特定类型的函数

c++ - GCC/G++ 编译器设置 GUI

rust - Rust 中有 POD 类型的概念吗?

rust - slice_mut 为 &mut [T]

arrays - 用于数组索引的正确类型是什么?

c++ - 等价于 C++ 中的 Swift 尾随闭包

c++ - 现在每个 Linux 发行版都附带 gcc/g++ 4.* 吗?

c++ - vector 迭代器转换

linux - open() 是从 libc 源代码的哪个位置获得链接的?

c++ - gcc exec if 和 else 也是...这是一个错误吗?