According to this MIPS instruction reference, there are two instructions (bgezal
and bltzal
) which perform a relative jump and link instead of just a relative jump if the branch is taken.
These instructions can be simulated with a bgez
or bltz
respectively, followed by a jal
, which means that both bgezal
and bltzal
should be classified as pseudo-instructions. However, both have opcodes assigned to them, hence they are classified as basic instructions.
What is the rationale for adding them to the basic instruction set and not making them pseudo-instructions? Also, why are only bgezal
and bltzal
included in the instruction set and not, for example blezal
, bgzal
etc?
jal
uses a semi-absolute target encoding (replacing the low 28 bits of PC), while bgezal
/ bltzal
are relative (adding an 18-bit signed displacement, imm16<<2
). How to Calculate Jump Target Address and Branch Target Address?
They are classic MIPS's only branch-and-link (instead of jump-and-link), so are important for position-independent relocatable code. (You can even use one to get the current PC into a register and find out where you're executing from, unlike with jal
).
You can encode bal
(unconditional relative function call) as bgezal $zero, target
.
You can get $ra=PC
with a not-taken bltzal $zero, anywhere
without needing any other setup. Doing that with bgezal
would need a less-than-zero input register that would take an insn to create. b...al
instructions always write $ra
even if the branch is not taken. You want this for PC-relative code, until MIPS32r6 gave us addiupc
for better PC-relative address generation.
Since they use an I-type instruction format like other b
ranch instructions, there's room in the encoding for one register, so it made sense to make it optionally conditional instead of just having a bal
instruction. The hardware logic for doing the "and link" was already there, and all the other relative branch instructions are conditional. Plus, having a condition that's not-taken for $zero
could be convenient for reading pc
.
Remember that MIPS instruction encodings were used directly as internal control signals in early MIPS hardware, so the one bit in the encoding that differs between them probably gets wired to an XOR gate that inverts (or not) the check on the sign bit. (As Konrad's answer points out, these branch conditions depend only on the MSB of the register because it's always against zero, so there's no latency of waiting for a 32-bit adder to produce a compare result.)
From http://www.mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.html
0000 01ss sss1 0001 iiii iiii iiii iiii BGEZAL
0000 01ss sss1 0000 iiii iiii iiii iiii BLTZAL
This lack of flexibility in instruction-encoding (because it directly drove internal control signals instead of needing much transformation in decoding) is perhaps why there isn't just a single bal
with a 28-bit range (from a 26-bit relative displacement). The hardware for relative branches was set up for I-type instructions with 16-bit immediates.
TL:DR: there are 2 conditional branch-and-link instructions because it was natural to implement an unconditional bal
in terms of one of them, and the other came along nearly for free.
MIPS b
(unconditional relative branch without link) is also a pseudo-instruction for beq $zero, $zero, target
, or at the assembler's choice, for bgez $zero, target
. (What is the difference between unconditional branch and unconditional jump (instructions in MIPS)?). The MIPS R3000 manual suggests beq $zero,$zero
. (And more clearly documents that $ra=PC
happens regardless of branching; That wasn't clear from the quick-reference sheets I was looking at while writing this answer originally.)
The compare-to-zero encodings only have one 5-bit register field, so they consume less coding space than beq
/ bne
. That's a likely reason for choosing bgezal
rather than beqal
as one of the pair of conditional branches to provide.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With