【问题标题】:Is this a GCC bug when using -falign-loops option?使用 -falign-loops 选项时这是 GCC 错误吗?
【发布时间】:2012-04-10 11:31:58
【问题描述】:

我正在使用这个选项来优化我们嵌入式架构中的 for 循环 (here)。但是,我注意到,当对齐需要添加多个 nop 指令时,编译器会生成一个 nop 后跟尽可能多的零 (0000)。

我怀疑这是我们编译器中的错误,但有人可以确认这不是 GCC 中的错误吗?

这是一个代码sn-p:

    __asm__ volatile("nop");  
    __asm__ volatile("nop");  

    for (j0=0; j0<N; j0+=4)
    {
        c[j0+ 0] = a[j0+ 0] + b[j0+ 0];
        c[j0+ 1] = a[j0+ 1] + b[j0+ 1];
        c[j0+ 2] = a[j0+ 2] + b[j0+ 2];
        c[j0+ 3] = a[j0+ 3] + b[j0+ 3];
    }

使用-falign-loops=8(或与您的架构相关的任何数字,超过所需的最小对齐)进行编译。您可以根据需要添加或删除 __asm__ 行以生成未对齐的循环体。

【问题讨论】:

  • 顺便说一句,我也会摆脱丑陋的手动循环展开,让 gcc 展开循环(默认情况下,它会在认为有意义时使用 -O3 执行此操作)。跨度>
  • @R.. - 显然,在现实世界中并非如此。这段代码实际上是我进行向量加法的基准的一部分。我有两个函数,带有上述代码的 vecadd() 和类似于您的建议的 vecadd_naive()。事实是我必须手动展开 16 次才能获得最佳性能,这比天真的版本要好一点。这是使用 -O3 和(可能是多余的)-funroll-loops。
  • @R..- 请记住,优化器用于展开循环的启发式方法是基于一些任意的规则集(好的,至少是任意的 w.r.t 可用选项)。您的考虑(例如,代码大小或寄存器使用)可能会有所不同,毕竟会导致更快的代码。我想这就是我看到的不同之处。
  • 您可以在循环之前添加#pragma 用于优化级别/展开决策参数,而不是手动展开它。我不确定这是否比自己展开循环更好或更丑陋......

标签: c gcc for-loop alignment memory-alignment


【解决方案1】:

使用gcc -S -o foo.s foo.c 生成汇编输出而不进行汇编。我怀疑你会在 asm.xml 中看到 .balign.p2align 指令。假设该指令旨在工作,我认为这是汇编程序中的错误。您也可能有意或无意地将代码放在非默认部分(即不是.text)中(例如,在其他一些内联汇编中放错了.data.section);通常,汇编器使用适当大小和数量的 nop 指令填充包含代码的部分,以及 0 字节用于包含数据的部分。

【讨论】:

  • 确实,编译器将.balign 8 指令插入到了正确的位置。不幸的是,我已经发现当没有给出明确的填充值时,汇编器会生成错误的序列。据我所知,该函数分配在.text 部分。我想知道是否有办法告诉编译器在使用-falign-loops=n 时使用填充值,比如使用.balignw 8,0x01a2 时?
  • 不管怎样,这是我们的实现所特有的,还是 GAS 中的一个错误?
  • 如果您编辑 gcc 源以更改它插入到输出程序集中以在您的平台上对齐的字符串,这绝对是可能的。或者您可以更改 GAS。如果维护人员可以确认问题存在,则上游可能会接受任何更改。
  • 哦,好吧,我想当您可以访问源代码时一切皆有可能......我希望有一个未记录的功能(作为与 align 指令类似语法的选项的扩展)。
  • 好的,这是一个非常便宜的解决方案。找到你的 gcc 正在搜索二进制文件的路径(它可能在 /usr/lib/gcc 或类似的目录下),并在那里放置一个名为 as 的 shell 脚本。让它通过sed 运行其输入,以进行必要的对齐修复并运行真正的as 二进制文件。
猜你喜欢
  • 1970-01-01
  • 2017-06-04
  • 2013-05-04
  • 1970-01-01
  • 1970-01-01
  • 2012-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多