How to right rotate a 64-bit value efficiently in ARM7 assembler?
The ARM7-command set offers efficient ways to right rotate 32-bit values by an arbitrary amount in assembler. For the 2nd operand of an operation it is even "for free" by specifying ror #n as shifter operand, but for 64-bit integers no direct support by the instruction set is given. Besides the special cases of rotating by 1, 31, 33 or 63 bit positi开发者_开发知识库ons (not to mention 0 or 32), I only know how to rotate a 64-bit value using four instructions (it's quite easy, so I don't write it here). In the four special cases I can reduce this to three instructions, but I don't know how to do it in general. So here is my question:
Given a 64-bit value in two registers, say R0 and R1, is it possible to right rotate this value by n positions (for arbitrary n) with just three ARM7 instructions?
If a register (e.g. r4) happens to hold the proper magic constant (1 shifted left by the desired left-rotate amount) I think one can do it in two instructions:
umull r3,r2,r1,r4 umlal r2,r3,r0,r4
Slower than using four single-cycle instructions, but even if one has to load r4 with the proper constant it's still more compact than the four-instruction methods.
If there is a solution to this, gcc also doesn't recognize it:
unsigned long long int reg64 = random_value;
unsigned int n = shift_value;
reg64 = (reg64 >> (n%64)) | (reg64 << ((64-n)%64));
results in the following:
n=1:
MOVS R2, R0, LSR #1
MOV R3, R1, RRX
ORR R2, R2, R1, ASL #31
n=2-31:
MOV R2, R0, LSR #n
ORR R2, R2, R1, ASL #32-n
MOV R3, R0, ASL #32-n
ORR R3, R3, R1, LSR #n
n=33-62:
MOV R3, R0, ASL #64-n
ORR R3, R3, R1, LSR #n-32
MOV R2, R0, LSR, #n-32
ORR R2, R2, R1, ASL #64-n
n=63:
ADDS R2, R0, R0
ADC R3, R1, R1
ORR R2, R2, R1, LSR #31
精彩评论