【问题标题】:powerpc-eabivle-gcc does not support e_and2i instructionpowerpc-eavivle-gcc 不支持 e_and2i 指令
【发布时间】:2020-06-03 09:04:28
【问题描述】:

我正在使用 NXP 的 GCC 4.9 VLE 编译器。我的目标是 e200z7 内核。我想禁用 MSR 寄存器的第 16 位。这是我正在使用的:

/* Disable MSR[EE] bit*/
        mfmsr   r6
        e_and2i r6,0x7fff
        mtmsr   r6

当我使用 powerpc_eabivle_4_9/bin/powerpc-eabivle-gcc 编译 .S 文件时,出现以下错误:

Error: unrecognized opcode: `e_and2i'

如何在没有and指令的情况下将其设置为0?

【问题讨论】:

  • 是的。它存在于 CFLAGS、LDLAGS 和 ASFLAGS 中。

标签: assembly gcc bit-manipulation powerpc opcode


【解决方案1】:

这真的是XY Problem。你最终会问如何用不使用and 指令的东西替换e_and2i r6,0x7fff。真正应该问的问题是“为什么e_and2i r6,0x7fff 会抛出一个“无法识别的操作码” 错误?

答案很简单。您的目标是 e200z7 内核。该内核使用可变长度编码 (VLE)。指令的长度可以是 16 位或 32 位。带有前缀 se_ 的指令长度为 16 位,e_ 的长度为 32 位。以句点 (.) 结尾的指令会更新条件寄存器 (CR)。

如果你查看Variable-Length Encoding (VLE) Programming Environments Manual你会发现没有2个操作数e_and2i指令但是有一个e_and2i.指令。对于 VLE,没有不更新 CRe_and2i 指令。如果您的代码不依赖 CR 被保留(可能是这种情况),您可以简单地将 e_and2i 更改为 e_and2i.。您的代码将如下所示:

mfmsr    r6
e_and2i. r6,0x7fff
mtmsr    r6

或者,您可以使用不更新 CR 的 3 操作数形式 e_andi。它看起来像:

mfmsr    r6
e_andi   r6,r6,0x7fff
mtmsr    r6

e_and2i.e_andi 被编码为长度为 32 位的指令,但是有一条长度为 16 位的 VLE 指令可以完成您想要的工作并且不会更新 CR。该指令是 2 个操作数 立即位清除 se_bclri。你的代码可以写成:

mfmsr    r6
se_bclri r6,16          ; Clear the 16th bit (bit 0 is MSB and bit 31 is LSB)
mtmsr    r6

与 Peter Cordes 的回答有关,他建议如下:

rlwinm r6,r6,0,17,15

此指令无法正确编码为 VLE 指令。但是有 VLE 等价物:

e_rlwinm r6,r6,0,17,15

【讨论】:

  • 这是一个比我更好的答案;我不知道 PowerPC 甚至有一个紧凑的指令格式。是否有 GCC 选项可以为其生成代码,希望可以优化到 se_bclri r6,16
  • @PeterCordes:主线 GCC 不支持 VLE。有一个支持它的 GCC 补丁版本 - NXP 的一个基于 GCC 4.9 的版本。是的,我刚刚检查过,您的示例简化为 se_bclri r3,16 se_blr 的函数
  • @MichaelPetch 感谢您的详细回答。我应该提出正确的问题。
【解决方案2】:

更新:请参阅 @MichaelPetch's answer 了解 VLE(可变长度编码)。我的回答只是对通用 PowerPC 的一个简单天真的回答,当紧凑的 16 位指令可用时,它不是最佳的。

如果您在 NXP 的 GCC 版本中应用了相同的技术,可以从 C 为您生成 VLE asm,it will use se_bclri r3, 16

当您不知道针对 ISA 的每个窥视孔优化时,询问编译器的一般技术非常有用。


像往常一样,询问编译器:

unsigned foo(unsigned x) {
    return x &= ~(1UL << 15);
}

compiles on Godbolt 与 GCC4.8.5 -O3 -mregnames

foo(unsigned int):
        rlwinm %r3,%r3,0,17,15
        blr

我认为rlwinm 可以在每台PowerPC 上使用,或者至少不是特别新的或罕见的。它需要一个位范围(开始/结束,可以环绕以只留下一个被屏蔽的位)和一个旋转计数(在这种情况下为零)。

【讨论】:

  • 应该是rlwinm %r3,%r3,0,17,15,不是吗?因为我想用 0 屏蔽第 16 位。
  • @Nee:PowerPC 从 MSB=0 开始计数位。 IDK 为什么 IBM 必须与众不同,让一切变得更加复杂,但他们确实做到了。
  • 抱歉,但我仍然无法理解这一点。我是初学者。是的,它从 MSB 0 开始计算。因此,我们需要从第 17 位开始的 1,它将环绕到第 15 位,将第 16 位保留为 0。我参考了 devblogs.microsoft.com/oldnewthing/20180810-00/?p=99465 的视觉效果。
  • @Nee:哦,对不起,我确实误读了这个问题。更新后,1&lt;&lt;16 是第 17 位(像正常人一样从底部开始)。打开一个godbolt选项卡后,我把它记错为第16位,而不是第16位,并且没有根据问题中的掩码检查它。
  • @MichaelPetch:哦,是的,我知道 IBM 的位编号约定(OP 也是如此)。这不是前 2 个 cmets 混淆的根源,只是我在“第 16 位”和1&lt;&lt;16 之间混淆了,忘记了 OP 所说的内容以及他们使用的 AND 掩码。我假设 OP 是从寄存器底部(LSB=0)开始计数位,而不是遵循 IBM 的位编号约定,而且看起来这确实是他们真正想要的。无论如何,我认为现在每个人都对此意见一致。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-15
  • 1970-01-01
  • 2015-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多