How to rotate a 64-bit value in an ARM7 assembler?

The ARM7 instruction set offers effective ways to right-rotate 32-bit values ​​by an arbitrary amount in assembler. For the second operand of the operation, it is even “free”, specifying ror #n as the shifter operand, but for 64-bit integers direct support for the instruction set is not specified. Besides the special cases of turning to 1, 31, 33 or 63 bit positions (not to mention 0 or 32), I know how to rotate a 64-bit value with four commands (this is quite simple, so I do not write it here). In 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 rotate this value by n positions (for arbitrary n) using only three ARM7 commands?

+3
source share
2 answers

If the register (for example, r4) has the correct magic constant (1 is shifted to the left by the right amount on the left), I think that this can be done in two instructions:

  umull r3, r2, r1, r4
  umlal r2, r3, r0, r4

Slower than using four single-cycle instructions, but even if you need to load r4 with the proper constant, it is even more compact than four instructions.

+2
source

If there is a solution to this, gcc also does not recognize it:

unsigned long long int reg64 = random_value;
unsigned int n = shift_value;
reg64 = (reg64 >> (n%64)) | (reg64 << ((64-n)%64));

leads to 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
+1
source

All Articles