使用 gcc -O3 优化时,为什么循环索引的类型会影响 gcc 的内部 GIMPLE 向量常量(但不会影响最终的 asm)?

With gcc -O3 optimization, why does the loop index's type affect gcc's internal GIMPLE vector constants (but not the final asm)?

提问人:Daisy G 提问时间:11/1/2023 最后编辑:Peter CordesDaisy G 更新时间:11/2/2023 访问量:54

问:

我创建了一个结构数组,这是我的源代码。

#include <stdio.h>
#include <stdlib.h>

#define N 256


typedef struct arc {
   int num;
} arc_t;

typedef double cost_t;

typedef struct  basket {
    arc_t *a;
    cost_t cost;

} BASKET;

static BASKET basket[N];
static BASKET *perm[N];

int main() {
     __asm__ ("########");
     int j;
   
    for ( j = 0; j < N; j++)
    {
    
        perm[j] = &(basket[j]) ;
    }
    __asm__ ("########");
    
    printf("%d\n",perm[1]->a->num);

    return 0;
}

至此,我定义了一个整数变量“j”。使用命令打印中间文件时,在我的标记位置(asm (“########”);)生成的中间文件中,有以下内容:gcc -O3 p.c -fdump-tree-vect-details -fopt-info-vec -S -mavx2

<bb 2> [local count: 10737416]:
  __asm__ __volatile__("########");
  vect_cst__13 = { 8, 8, 8, 8, 8, 8, 8, 8 };
  vect_cst__22 = { 16, 16, 16, 16, 16, 16, 16, 16 };
  _27 = (long unsigned int) &basket;
  vect_cst__28 = {_27, _27, _27, _27};

但是,当我定义“long j”时,它会产生以下中间文件:

  <bb 2> [local count: 10737416]:
  __asm__ __volatile__("########");
  vect_cst__14 = { 4, 4, 4, 4 };
  vect_cst__19 = { 16, 16, 16, 16 };
  _23 = (long unsigned int) &basket;
  vect_cst__24 = {_23, _23, _23, _23};

这是差异的一部分,但最让我困惑的是,在 Peter Cordes 的帮助下,我们推测中间代码的差异可能是由于 int 和 long 数据类型的不同大小造成的。
但是它只是一个数组索引,那么为什么它的数据类型会产生这种影响呢?我在 和 的两种情况下都打印了“basket[j]”的前四个地址,它们是相同的。gcc 版本为 10.3.0
jint jlong j

由于此时中间文件存在差异,我怀疑前端编译器可能应用了不同的优化。我应该在哪里查找与此相关的信息?GCC 如何分析结构数组?

gcc 器-构造 编译器优化 自动矢量化 gimple

评论

0赞 Peter Cordes 11/1/2023
如果你对循环计数器做了任何事情,而不是索引连续元素,你可能会得到一些最终的 asm 代码生成,它实际上使用了值的向量(并将每个元素递增了 4 或 8)。与这种情况不同的是,这些(几乎可以肯定)只是在自动矢量化过程中发明的临时数据,并在生成 asm 之前再次优化。当然不会改变。您应该尝试 或 ,尽管在这两种情况下,我希望 GCC 缩小循环计数器以匹配其使用的大小。j&basket[j]arr[j] = j;sum += j;
0赞 Daisy G 11/1/2023
@PeterCordes我想知道为什么这些临时工件是不同的,但我无法确定该过程的哪个部分生成了它们。
0赞 Peter Cordes 11/1/2023
我对正在发生的事情的心智模型是,GCC 发明了一个 32 字节的向量,其中填充了值,作为弄清楚它必须使用什么以及如果需要它可能使用什么的早期步骤的一部分。但它最终根本不需要它,所以它在任何地方都不存在,也没有不同的宽度。使用 4 字节与 8 字节,展开原始循环足以用值填充一个 SIMD 向量,生成其中的 4 或 8 个,需要增加 4 或 8。jjj
0赞 Daisy G 11/1/2023
@PeterCordes 在添加一些地址后,它最终将被使用并分配给“perm”数组。
0赞 Peter Cordes 11/1/2023
哦,对了,你正在做一些非常接近的事情,只是用指针。 只是.对于窄指针宽度,仍然会发生隐式转换指针宽度。(或者对于 32 位代码,我期望循环计数器会缩小到 32 位)。我不知道为什么 GCC 在发明一个 8x 值的向量之前没有“注意到”这一点,如果我对该向量常数的猜测是正确的。arr[j] = j&basket[j]basket + jint jint64_t jj

答: 暂无答案