Assembly ARM组件中32位字内的高效字节旋转
假设我们有一个32位寄存器,它由四个字节组成Assembly ARM组件中32位字内的高效字节旋转,assembly,arm,bit-manipulation,Assembly,Arm,Bit Manipulation,假设我们有一个32位寄存器,它由四个字节组成R=b0 | b1 | b2 | b3 我想做的是计算R',这样R'=(b0沿着这些线: (源值为R0,结果为R0) 使用LDR“=”因为我很懒,所以可能存在一种更优化的方法来生成这些掩码 编辑 (为@PeterCordes干杯) 是的,其中一个移位可以嵌入到和中,我们也可以稍微改变操作顺序,使用不同的掩码,但结果将大致相同 在“C”中,这看起来像这样: unsigned byte_rot2l(unsigned x) { unsigned re
R=b0 | b1 | b2 | b3
我想做的是计算
R'
,这样R'=(b0沿着这些线:
(源值为R0,结果为R0)
使用LDR“=”因为我很懒,所以可能存在一种更优化的方法来生成这些掩码
编辑
(为@PeterCordes干杯)
是的,其中一个移位可以嵌入到和中,我们也可以稍微改变操作顺序,使用不同的掩码,但结果将大致相同
在“C”中,这看起来像这样:
unsigned byte_rot2l(unsigned x) {
unsigned result;
result = ((x<<2) & 0xfcfcfcfc);
result |= ((x>>6) & 0x03030303);
return (result);
}
编辑#2
第二行由汇编程序从文字池转换为32位常量的PC相对负载,可以替换为:
MVN R1,R2
这样就无需将0x03030303存储在文字池中。然而,我很难理解为什么Godbolt上的gcc不使用这种优化,不管我尝试了什么编译器选项。有人有想法吗?我们可以通过移位实现旋转并屏蔽我们不想要的位来获得想要的效果。这给了我们类似于C中的代码:
/* byte-wise right rotate */
unsigned brrot(unsigned R, x)
{
unsigned mask;
mask = 0x01010100U - (0x01010101U << R);
return ((x & mask) >> R | (x & ~mask) << (8-R));
}
你想要ARM还是thumb汇编?你能把lsr
折叠成另一条指令吗,比如和?可能没有移位的掩码,所以只适用于编译时常量旋转。@PeterCordes不是真的,我也考虑过这一点。出于兴趣,你经常用C89或一些旧的C编译器编程吗?因为最近我很少使用只需在函数的顶部声明未赋值的变量(即,我期望<代码> const无符号掩码=0x0101…< /代码>)。我认为首先声明所有变量是更干净的。,所以我尽量避免它们。其中一个移位不应该是8-R吗?32位ARM是否有像AArch64一样的重复位模式立即体?我认为AArch64可以使用掩码作为AND的立即体。无论如何,如果你要加载两个常量掩码,你可以将移位折叠成AND之一,对吗?比如和r0,r2,lsl#2
。@PeterCordes ARM有m、 但仅在thumb模式下。IIRC总是导致生成一个4字节的指令。我也考虑过使用thumb代码,但结果并没有更好,所以为了更清晰,我使用了ARM代码。@fuz我再次编辑了答案,并在那里提出了一个问题…@tum_u。我认为两个编译器都没有这种优化,我想可能您可以尝试在相应的bug追踪器上提出增强请求。
MVN R1,R2
/* byte-wise right rotate */
unsigned brrot(unsigned R, x)
{
unsigned mask;
mask = 0x01010100U - (0x01010101U << R);
return ((x & mask) >> R | (x & ~mask) << (8-R));
}
ldr r2, =0x01010101 @ load 0x01010101
sub r3, r2, #1 @ compute 0x01010100
sub r2, r2, r3, lsl r0 @ compute mask
and r3, r1, r2 @ compute x & mask
bic r2, r1, r2 @ compute x & ~mask
lsr r3, r3, r0 @ compute (x & mask) >> R
rsb r0, r0, #8 @ compute 8 - R
orr r0, r3, r2, lsl r0 @ compute (x & mask) >> R | (x & ~mask) << (8 - R)
sbc r2, r2, r3, lsl r0 @ compute mask