Formalizing the comments into an answer
J
/JR
can be emulated with JAL
/JALR
as the latter performs a super-set of the operations of the former.
As @Jester pointed out, routines (functions in C jargon) must be careful to preserve their return address present in $ra
.
Unless the routine is a leaf routine (one that doesn't do any call) $ra
must be saved somewhere anyway.
Actually both JAL
/JALR
and J
/JR
can be implemented one in terms of the other:
Emulate JAL
/JALR
with J
/JR
Original Emulated
jal foo la $ra, ret_label
j foo
ret_label:
Emulate J
/JR
with JAL
/JALR
Original Emulated
j foo prolog:
addi $sp, $sp, -4
sw $ra, ($sp)
jal foo
epilog:
lw $ra, ($sp)
addi $sp, $sp, 4
For this to work, the code must return to epilog
. It is assumed that $ra
is mostly preserved in routines (hence the names of the labels).
Many thanks to @EOF for point out a mistake in this snippet.
As @Peter pointed out, the access to the $pc
leads to an easier (for humans) emulation of JAL
/JALR
.
As @EOF pointed out, some RISC machine actually have only one instruction for JAL
/JALR
and J
/JR
given their innate entanglement.
Considering that jumps and call happen very often in a typical program, being able to implement easily (and executing them fast) is mandatory for any successful ISA.