ARM branches
| Opcode | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| O8 | RN | RD | RS | OPC2 | RM | |||||||||||||||||||||||||||
| COND | OOOO | OFFSET | ||||||||||||||||||||||||||||||
| bx[cond] Rm (aka ret) | cond | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | SBO | SBO | SBO | 0 | 0 | 0 | 1 | Rm | |||||||||||||||
| b[cond] <target addr> (aka jmp) | cond | 1 | 0 | 1 | 0 | 24_bit_offset | ||||||||||||||||||||||||||
| bl[cond] <target addr> (aka call) | cond | 1 | 0 | 1 | 1 | 24_bit_offset | ||||||||||||||||||||||||||
The bx lr instruction is most like and aliased to the x86 ret (no imm) instruction.
The b instruction is most like and aliased to the x86 jmp label instruction (32MB limit).
The bl instruction is most like and aliased to the x86 call label instruction (32MB limit).
A mov lr,pc; b Rm; pair should (manually/explicitly) be used instead of an x86 call register instruction.
Note that since call/return on the ARM uses the lr (link register) instead of the system stack,
there is no equivalent form of the x86 ret imm instruction, however you can of course use
add sp,NN; pop {pc} or perhaps better yet pop {Rm-Rn,pc} to mimic it.
It is also quite common to see lr being popped followed by a bx lr, which is perhaps understandable for manually written code,
but I can think of no good reason for a compiler to follow suit, given that the lr bit is adjacent to the pc bit, so it’s
not like other register restores c/would run interference, and it should instead pop pc directly rather than into lr and jumping,
and obviously that way emit one less instruction.
Note that eg #ilASM{call "libc", "printf"} has to jump through several hoops: a couple of symtab entries, an entry in the string table, a relocation entry, and a ".word printf" near the start of the data section [fetchable via ip], as well as emitting the three instructions "ldr rN, [ip+imm]; mov lr, pc; bx rN;". (At a bare minimum and at this stage that’s all a bit of a guess!)
There is no (deliberate) support for entering thumb mode via bx, that is, in Phix, which
should not be surprising since there is (as yet) no way to generate any thumb instructions.
The blx instruction is not supported, if necessary replace eg "blx r4" with "mov lr,pc" and "bx r4".
| Phix | Traditional branches | Sometimes Better |
function gcd(integer a,b)
while a!=b do
if a>b then
a -= b
else
b -= a
end if
end while
return a
end function
|
gcd: cmp r0,r1
beq stop
blt less
sub r0,r1
b gcd
less:
sub r1,r0
b gcd
stop:
bx lr
|
gcd: cmp r0,r1
subgt r0,r1
sublt r1,r0
bne gcd
bx lr
|
The cut-off point for sticking with traditional branches over unconditional instructions is quite small: typically 4..6 instructions, so I’m told.