ARM immediate value encoding (2014)
alisdair.mcdiarmid.org
alisdair.mcdiarmid.org
It's so complicated that the assembler in binutils actually implements it by brute-forcing!
https://github.com/bminor/binutils-gdb/blob/c40d7e49cf0a6842...
That means you can write MOV, r0, #-1 (equivalent to #0xFFFFFFFF) and the assembler will emit a MVN r0, #0 to fulfill your needs. This increases the number of constants that can be directly assigned.
On the other hand, that would mean zero couldn't be encoded, but you don't need a zero for most maths as it doesn't do anything (and you could use a zero register.)
Edit to add: the even shift is a problem, but you could use 7 bits of number, 1 implicit leading 1 bit, and 5 bits to cover any 32-bit shift.
So good that they got rid of it in their new chips.
AArch64 already has similar code density to x86-64 anyway.
I find myself using (apparently unnecessary) 'LDR' instructions because of this sort of thing all the time. And that adds up, in Cortex-M chips with kilobytes of program memory.
The following classes of constant are available in Thumb-2:
•Any constant that can be produced by shifting an 8-bit value left by any number of bits.
•Any replicated halfword constant of the form 0x00XY00XY
•Any replicated halfword constant of the form 0xXY00XY00
•Any replicated byte constant of the form 0xXYXYXYXY
See page 92 here: http://hermes.wings.cs.wisc.edu/files/Thumb-2SupplementRefer...
There is also MOVT which will set the top 16 bits of a register to any 16-bit value and not affect the bottom 16bits
And there is MOVW (MOV.W) which will set the bottom 16 bits to any value and zero the top 16 bits
MOVW + MOVT allows loading any 32-bit value in 2 instructions (8 bytes)
Regarding the 00XY00XY and XY00XY00 forms: I'm going to have to sleep on this, but this is a bit of mystery to me so far. I'm going to have to keep an eye out for those sorts of constants now! Maybe they're actually quite common?? - I suppose this will certainly let you form many kinds of mask useful for SIMD operations.
So, is it the case that with ARM, you _may_ be able to do the same add in one op, but it's worst case appears to be 4 ops for the full range of immediate values?
Edit: Also, ARMv8 has dedicated instructions for for pc-relative loads and jumps.
On older ARMs, either do a load immediate followed by an immediate arithmetic, like so:
MOV R0, 0x0100
ADD R0, R0, 0x01
Or use a PC relative load: LDR R0, [PC, offset where you stored 0x101]
Which the assembler allows you to abbreviate as: LDR R0, =0x101
And it will find a spot for 0x101 and generate the correct PC relative load.When writing ARM assembly, the assembler (at least the ones I've seen) abstract this detail away from you.
You can use
ldr r0, =0xff000000
and the assembler will emit a MOV if it can, and if it can't it will put the value somewhere in RAM and use LDR to load it up.ARM is fun.