有人可以给我看一个 C++ 的例子吗?我正在尝试练习我的汇编语言技能,从我得到的语言是 powerpc,我们正在寻找 44 位移到 r0 内部的右侧,从那里我们是提取前 8 位
extrdi r0, r0, 8,44
ISA 说
extrdi
是“提取并右对齐立即数”,它是 rldicl
(“向左旋转双字立即数并向左清除”)的扩展助记符 - v2.07 pg 717。所以你的陈述是等效的到rldicl r0, r0, 52, 56
。
因此,您想要提取从位置 44 开始的 8 位,然后对其进行右对齐,这将使其成为最低有效的 8 位。值得注意的是,IBM 位数字与您可能期望的相反:
conventional bit = 63 - IBM bit
。因此 IBM 位 44 到 51 是“常规”位编号 12 到 19。
我们只需向下移位,使位 12 变为位 0,位 19 变为位 7 - 移位 12 位。然后我们需要屏蔽它,这样我们只得到最低有效的 8 位。
unsigned long extrdi(unsigned long a) {
return (a >> 12) & 0xff;
}
查看 godbolt.org:https://godbolt.org/z/rGe3EW,我们看到这确实是:
extrdi:
rldicl 3,3,52,56
blr
.long 0
.byte 0,0,0,0,0,0,0,0
(r3是参数和返回寄存器)
根据PowerPC助记符文档,
extrdi
表示从b位开始提取n位,然后右对齐。
以8位整数来说明:
extrdi r0, r0, 2, 3
r0: A B C D E F G H
| |
+---+
2 2+3-1
After extraction: 0 0 C D E 0 0 0
After justification: 0 0 0 0 0 C D E
我们可以如下实现(64位):
unsigned long extrdi_soft(unsigned long ry, unsigned n, unsigned b) {
unsigned offset = (64 - b - n);
// Generate the n-bit mask beginning from position b
unsigned mask = ((1UL << n) - 1) << offset;
// Do mask and right-justify it
return (ry & mask) >> offset;
}
与真实的比较
extrdi
:
unsigned long extrdi_hard(unsigned long rs) {
unsigned long ra = 0;
asm("extrdi %1, %0, 8, 44"
:"=r"(ra)
:"r"(rs));
return ra;
}
// extrdi_hard(0x1234567UL) == extrdi_soft(0x1234567UL, 8, 44)
extrdi rs, ry, n, b
实际上是 rldicl rs, ry, b+n, 64-n
的助记符。该指令的意思是向左旋转然后向左清除。所以我们有另一种方式来实现extrdi
:
unsigned long rotl64(unsigned long rs, unsigned n) {
return (rs << n) | (rs >> (64-n));
}
unsigned long rldicl(unsigned long rs, unsigned sh, unsigned mb) {
return rotl64(rs, sh) & ((1UL << (64 - mb)) - 1);
}
unsigned long extrdi(unsigned long ry, unsigned n, unsigned b) {
return rldicl(ry, b+n, 64-n);
}