How to avoid repetitive syscalls and moves in MIPS Assembly?

Kevin Mora

Here's a fragment of my code and as you can see the only difference between these three is the move from $v0 to $t0, $t1, or $t2. Does anyone know if there's a way to simplify these.

                        .text
    main:               #start of program
    loop:
    #read the ints (store them in t0, t1, t2)
    la  $a0, input_msg  #load input_msg into $a0 to prepare for syscall
    
    li  $v0, 4      #set $v0 to 4, which will print what $a0 points at
    syscall         #make the syscall
    li  $v0, 5      #prepare $v0 for reading an int
    syscall         #read the int
    move    $t0, $v0    #move the information from $v0 to $t0
    
    li  $v0, 4      #set $v0 to 4, which will print what $a0 points at
    syscall         #make the syscall
    li  $v0, 5      #prepare $v0 for reading an int
    syscall         #read the int
    move    $t1, $v0    #move the information from $v0 to $t1
    
    li  $v0, 4      #set $v0 to 4, which will print what $a0 points at
    syscall         #make the syscall
    li  $v0, 5      #prepare $v0 for reading an int
    syscall         #read the int
    move    $t2, $v0    #move the information from $v0 to $t1
Erik Eidt

There's no way to simplify; that is already minimal, unless you want to write a loop that stores to an array in memory1.

Any syscall requires a function code to be placed into $v0.

So, another syscall requires repurposing of the $v0 register resulting in loss of the prior value unless it is preserved elsewhere.

This is one of the differences between assembly / machine code and other programming languages.  Other languages have logical variables that have names, types, scope/lifetime, and hold values at runtime, the same value until changed.  A local variable will hold its value over a system or library call (unless explicitly being passed by reference, or in higher level languages than C, is closed over).

Whereas in machine code we have physical storage, namely registers and memory, and, especially the registers are often being repurposed.  So, that is something that the compiler and assembly programmers just have to deal with when mapping logical variables of our algorithms into the physical storage machine code.


Footnote 1: But if you store in a loop, you'd have to reload them when you want to use them. This would mean more instructions executed, but could mean smaller code size if loop overhead + reload overhead is smaller than 2 of the 3 copies of the loop body. In this case it would be close to break even either way.

As Nate suggested, you could wrap up the repetitive stuff in a macro to keep your source tidier, while producing the same machine instructions. Then your source could look like la $a0, input_msg ; PROMPT_AND_READ_INT $t0, then again for $t1, etc.


However, to add to that, this is how the MIPS and RISC V and some other ABI's are defined, so there's no way around this in those environments.  But these are not the only way things could be defined.

We can imagine another ABI architecture where the result of a function (or syscall) is pushed onto the call/thread stack.  This would mean that multiple calls can be made and the results will accumulate (on stack).  While this might be superb for some scenarios, it would be detrimental to others, and analysis has shown that doing the minimum: returning values in registers instead, is best on average.  Letting the caller push function/syscall results onto the stack, when desired, is virtually equivalent in performance to always doing it, and then, when not necessary, not doing so saves memory references (write to the stack followed by read from the stack) which also making the code shorter/denser (also a known win).

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related