我的理解是ARMv8 A64汇编中的立即参数可以是12位长。如果是这种情况,为什么这行汇编代码:
AND X12, X10, 0xFEF
产生此错误(使用gcc编译时)
Error: immediate out of range at operand 3 -- `AND X12, X10, 0xFEF'
有趣的是,这行汇编代码编译得很好:
ADD X12, X10, 0xFEF
我正在使用aarch64-linux-gnu-gcc(Linaro GCC 2014.11)4.9.3(预发布)
答案 0 :(得分:9)
与A32"灵活的第二操作数"不同,A64中没有通用的即时格式。对于即时操作数数据处理指令(忽略无聊和直接的指令,如移位),
add{s}
,sub{s}
,cmp
,cmn
)采用12位无符号立即数,可选的12位左移。movz
,movn
,movk
)可以选择16位立即移位到寄存器中的任何16位对齐位置。adr
,adrp
)需要立即签名21位,虽然没有直接指定它的实际语法 - 为此你必须这样做求助于汇编程序表达技巧以生成适当的"标签"。and{s}
,orr
,eor
,tst
)立即采用"位掩码",我不确定我甚至可以解释一下,所以我只引用the mind-bogglingly complicated definition:这样的立即数是32位或64位模式,被视为大小为e = 2,4,8,16,32或64位的相同元素的向量。每个元素包含相同的子模式:1到1-e-1非零位的单次运行,旋转0到e-1位。这种机制可以生成5,334个唯一的64位模式(2,667对模式及其按位反转)。
答案 1 :(得分:5)
这是根据Notlikethat的回答中引用的机制转储所有合法位掩码的一段代码。希望它有助于理解生成位掩码的规则是如何工作的。
#include <stdio.h>
#include <stdint.h>
// Dumps all legal bitmask immediates for ARM64
// Total number of unique 64-bit patterns:
// 1*2 + 3*4 + 7*8 + 15*16 + 31*32 + 63*64 = 5334
const char *uint64_to_binary(uint64_t x) {
static char b[65];
unsigned i;
for (i = 0; i < 64; i++, x <<= 1)
b[i] = (0x8000000000000000ULL & x)? '1' : '0';
b[64] = '\0';
return b;
}
int main() {
uint64_t result;
unsigned size, length, rotation, e;
for (size = 2; size <= 64; size *= 2)
for (length = 1; length < size; ++length) {
result = 0xffffffffffffffffULL >> (64 - length);
for (e = size; e < 64; e *= 2)
result |= result << e;
for (rotation = 0; rotation < size; ++rotation) {
printf("0x%016llx %s (size=%u, length=%u, rotation=%u)\n",
(unsigned long long)result, uint64_to_binary(result),
size, length, rotation);
result = (result >> 63) | (result << 1);
}
}
return 0;
}