当前位置: 首页 > 知识库问答 >
问题:

gcc:为简单循环生成的奇怪 asm

芮雪风
2023-03-14
m68k-linux-gnu-gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
CFLAGS = -Wall -Werror -ffreestanding -nostdlib -O2 -m68000 -mshort

我非常困惑为什么gcc会为const数组上的简单for循环生成这种(看似)非最佳代码。

const unsigned int pallet[16] = {
  0x0000,
  0x00E0,
  0x000E,
  ...
  0x0000
};

...

volatile unsigned long * const VDP_DATA = (unsigned long *) 0x00C00000;

...

for(int i = 0; i < 16; i++) {
  *VDP_DATA = pallet[i];
}

结果:

 296:   41f9 0000 037e  lea 37e <pallet+0x2>,%a0
 29c:   223c 0000 039c  movel #924,%d1
 2a2:   4240            clrw %d0
 2a4:   0280 0000 ffff  andil #65535,%d0
 2aa:   23c0 00c0 0000  movel %d0,c00000 <_etext+0xbffc2c>
 2b0:   b288            cmpl %a0,%d1
 2b2:   6712            beqs 2c6 <main+0x46>
 2b4:   3018            movew %a0@+,%d0
 2b6:   0280 0000 ffff  andil #65535,%d0
 2bc:   23c0 00c0 0000  movel %d0,c00000 <_etext+0xbffc2c>
 2c2:   b288            cmpl %a0,%d1
 2c4:   66ee            bnes 2b4 <main+0x34>

我主要关心的是:

为什么无用的第一个元素比较在2b0?这永远不会命中,也永远不会被分支回。它最终只是第一次迭代的重复代码。

    < li >有没有更好的方法来编写这个非常简单的循环,这样gcc就不会产生这种奇怪的代码? < li >有没有我可以利用的编译器标志/优化?< code>O3只是展开循环,我也不希望这样,因为在这部分代码中,空间比速度更重要。 < li >也许我过于谨慎,但我认为这不会是最难生成的代码。我原以为会有更多类似的东西(可能是错的,但你已经明白了):
lea pallet,%a0
movel #7,%d0
1:
movel %a0@+,c00000
dbra %d0,1

我明白,我必须在我的代码中更加明确一些,才能让它以长块的形式编写。我在这里的主要观点是,为什么gcc似乎无法弄清楚我的意图,即我只想将此数据转储到此地址。

另一个观察结果:

共有1个答案

幸阳波
2023-03-14

我一直在玩GCC和68k代码生成,我发现它不能再为68k系列生成像样的代码,尤其是68000。

代码几乎不正确,但是没有优化(或者我应该说,它似乎是DE优化的?)。您应该首先尝试使用 -Os 而不是 -O2。即使这样,您也会在生成的代码中遇到许多无用的 insns。

我的猜测是,虽然GCC中的实际体系结构支持迅速向前发展,但68k的后端并没有得到适当的维护,只是用最少的努力保持正确。

 类似资料:
  • 使用方式如下: 这是有效的解决方案吗?如果删除未使用的“魔术”变量 - 我在返回字符串后有分割错误。做错了什么? $gcc--version gcc(Debian 4.4.5-8)4.4.5 $uname-Linux深度站(挤压)2.6.32-5-686#1 SMP 5月10日星期五08:33:48 UTC 2013 i686 GNU/Linux

  • 问题内容: 我尝试从0.1循环到2.0,然后将输出打印到控制台。但是我得到了如下奇怪的输出: 源代码: 为什么它不打印确切的数字而不是像点呢?另外,使用代替还有什么区别,因为我不知道如何增加0.1? 问题答案: 这是正常的。它是浮点型固有的;像0.3这样的数字不能作为精确值存储在二进制文件中,因此您会逐渐积累错误。参考资料: Python手册,Wikipedia,Princeton CS的技术说明

  • 问题内容: 在分析这里最近一个问题的结果时,我遇到了一个非常奇怪的现象:显然HotSpot的JIT优化的额外一层实际上减慢了我的计算机的执行速度。 这是我用于测量的代码: 该代码非常微妙,所以让我指出一些重要的方面: “普通索引”变体使用直接变量作为数组索引。HotSpot可以轻松确定整个循环的范围并消除数组边界检查; by的“ masked index”变体索引实际上等于,但是通过AND-mas

  • 我刚开始学习Haskell,但是现在没有循环是非常令人沮丧的。我想出了如何为函数编写循环。然而,我的问题是,我想在迭代循环时输出一些结果。似乎我必须使用debug来执行这个简单的任务。 所以现在我只想举一个例子,说明如何在主结构中打印字符串10次。 换句话说,我想这样做10次: 谢谢。我觉得这对我的任务很有启发。

  • 我知道movzx可以用于打破依赖关系,但我偶然发现Clang和GCC都使用了movzx,我真的看不出它们有什么好处。下面是我在godbolt上尝试的一个简单示例: 对于gcc12-O3: 如果我理解正确,这里的第一个movzx打破了对前一个eax值的依赖,但是第二个movzx在做什么?我不认为它可以打破任何依赖,也不应该影响结果。 有了clang14-O3,就更奇怪了: 它在movzx似乎更合理的