6

I signed up because I've been googling forever for an answer to this question and can't find one.

I'd like to know if the jump instructions WITHOUT linking are strictly necessary in MIPS?

I can imagine for example that using "AL" versions when not required would incur some power penalty, but is there any situation (that's not completely contrived or could be coded around relatively simply) where ONLY J/JR would work?

Thank you!

Colin Weltin-Wu
  • 347
  • 1
  • 2
  • 10
  • 4
    They are not strictly necessary, but you'd have to be careful to preserve `$ra`. – Jester Dec 16 '16 at 01:26
  • If you can emulate JAL by getting an address into `$ra` some other way, then you don't need it. But I don't know MIPS well enough to know if there's a PIC way to do that. – Peter Cordes Dec 16 '16 at 04:17
  • C has the `goto` statement, which seems to work like a J instruction. The `break` and `continue` statements might also have a say in this too. – Taylor Hansen Dec 16 '16 at 05:50
  • On RISC-V, the jump-and-link instruction specifies a destination register (rather than using `$ra` always). To jump *without* linking, one simply uses the zero-register as the destination. – EOF Dec 16 '16 at 06:20

1 Answers1

6

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.

Margaret Bloom
  • 41,768
  • 5
  • 78
  • 124
  • The emulation of `J`/`JR` doesn't work that way, since the control flow doesn't return, so the stack adjustment is not undone by this code. Nevertheless, +1. – EOF Dec 16 '16 at 14:14
  • @EOF Yes, of course! Brainfart. I meant something like 1) save `$ra` 2) do the jumps with `jal`/`jalr` 3) restore `$ra`. Fixing the answer. Thanks – Margaret Bloom Dec 16 '16 at 14:52
  • 1
    Yeah, basically just treat this function like a non-leaf function regardless of whether it actually *is* a leaf function. – EOF Dec 16 '16 at 14:54
  • Thanks this makes perfect sense. To take this even further, I'd be curious to the impact of removing one pair versus the other in terms of code size/speed. – Colin Weltin-Wu Dec 16 '16 at 15:35
  • For example, if I were to remove J/JR, the compiler might be able to rearrange the code to use branches. I realize this is very pedantic, just curiosity. – Colin Weltin-Wu Dec 16 '16 at 15:40
  • 2
    @ColinWeltin-Wu: There's another aspect to having a clear distinction between function calls and jumps: A function call gives extra information about *future jumps* to the processor (namely, the `return` from the called function). Without this information, `return` is a fairly expensive operation, since it's an absolute branch, which means *branch target prediction* gets involved. OTOH, if the processor keeps around a small hardware stack of return addresses, the branch target is known well in advance, allowing prefetching and pipelining. – EOF Dec 16 '16 at 17:01