1

Arm mov 有一个限制,即立即数必须是 2 的倍数旋转的 8 位,我们可以这样写:

mov ip, #0x5000

但我们不能这样写:

mov ip, #0x5001

0x5000 可以拆分为 0x5000 + 1,我的意思是,一个有效的立即数和一个小数的总和。

那么对于给定的 32 位数字,如何快速找到最接近的有效立即数?像这样:

uint32 find_imm(uint32 src, bool less_than_src) {
...
}

// x is 0x5000
uint32 x = find_imm(0x5001, true);
4

2 回答 2

2

很简单,看它们之间的距离。0x5001 = 0b101000000000001。15 位有效数字,因此它会以 8 位立即数为您提供两条指令。还要记住在您的测试中进行旋转,如果有足够的零 0x80000001 并且您将其旋转到 0x88000000 或 0x00000003 附近,这距离测量值之间的距离只有两位有效数字。因此,立即进行,执行类型测试之间的距离,旋转一步,再次执行测试,然后重复直到发生所有可能的(反向)旋转,然后选择指令数量最少的一个/立即。

gnu 已经这样做了,gas 是开源的,所以如果你愿意,你可以去获取他们的代码。当您使用加载地址技巧时:

ldr rd,=const

如果该 const 可以在单个立即移动指令中解决,那么它将其编码为

mov rd,#const

如果它不能,那么它会尝试找到一个放置单词的位置并将其编码为 pc 相对负载:

ldr rd,[pc,#offset]
...
.word const
于 2013-07-20T13:11:28.390 回答
1

没有一个直接的规则或函数来寻找构建价值的方法。一旦一个值超过了可以从立即值轻松加载的值,您通常通过在数据部分中定义它并从内存中加载它来加载它,而不是从立即值构造它。

如果您确实想从两个立即值构造一个值,则必须考虑各种操作,包括:

  • 添加两个立即数。
  • 减去两个立即数。
  • 将两个立即数相乘。
  • 更深奥的指令,例如一些将 32 位寄存器分成多个通道的“SIMD”指令。

如果你必须去三个直接值,还有更多的组合。人们可以在减少搜索的可能性中找到一些模式,但其中一部分仍然是“蛮力”搜索。通常,使用复杂的指令序列没有意义,因为您可以简单地从内存中准备好的位置加载数据。

ARM 汇编器有一个指令形式来帮助这个

LDR Rd, =const

当汇编器看到这一点时,它会将const值放入文字池中并生成一条指令以从池中加载该值。如果您使用不同的汇编程序,它可能没有相同的指令形式,但您可以手动编写必要的代码。

于 2013-07-20T12:45:12.343 回答