简体   繁体   中英

C to MIPS assembly while loop

C language

while (save[i] == k) 
i += 1;

i→ $s3

k → $s5

base addr of save → $s6
        
          sll $t1, $s3, 2        #$t1 = 4*$s3
          add $t1, $t1, $s6      #$t1 = address of save[i]
          lw $t0, 0($t1)         #t0 = save[i]
          bne $t0, $s5, Exit     #$t0!=$s5 Exit
    Loop: addi $s3, $s3, 1       #i+=1
          addi $t1, $t1, 4       #point to next cell
          lw $t0, 0($t1)         #t0 = save[i]
          beq $t0, $s5, Loop     #$t0==$s5 loop again
    Exit:

That I want to ask, is necessary the line addi $s3, $s3, 1 ?

Because, anyway $ t1 increases by 4.

The C code and assembly code don't actually match. The assembly code has been optimized to use pointers instead of array references, and, the exit condition of the loop has also been replicated once outside the loop, allowing the loop structure to use a more efficient do while loop (more efficient during iteration because it saves an unconditional branch at the end compared with straightforward code for a while loop).

Let's note that these optimizations are not just possible in assembly, but also doable in C.

The C version of the assembly is as follows:

int *sp = save + i; // in C this addition is automatically scaled by 4
if ( *sp == k ) {
    do {
        i++;
        sp++;   // this C +1 is scaled so really is +4
    } while ( *sp == k );
}

Sure, this is logically equivalent to the other.

Your question is: do we need the i++; ?

One answer is: No, not in the loop. You are correct that the loop does not use i and would access the same elements of the array, and exit at the same point as the original, simpler C loop.

Another answer is: Yes, if i is used after the loop! This loop does very little but examine some memory. We have to ask: what is the purpose of the loop, if not to set i for some code following the loop? Here perhaps the purpose of the loop is to count duplicates, which would result in i being the "output"/desired result of the loop: containing that count of duplicates when it ends and the next statement after is run.

This is one reason why it is difficult to reason over small snippets of code — essentially we cannot tell what comes next and if i will be used or not. But if i isn't used, then there is no value to the loop..


If we were to experiment with putting this into a compiler, we would be forced to change the snippet into a complete function. The compiler won't accept code statements smaller than a function.

A whole function definition is the smallest piece of code you can give the compiler (code snippets outside a function definition are not legal statements in the C language), and that wrapping makes the environment for the code snippet clear:

  • parameters are given inputs
  • local variables are temporary and go out of scope
  • return values are expected outputs.

(Of course there are also side effects, for example, like sorting something that outlasts the function, or creating heap objects that outlast the function.)

Wrapped in a function, we could then observe for sure then whether a local variable i is used after the loop or not.


Of course, there's another way to compute i 's value after the loop, without incrementing it during the loop. After the loop the following statement will recover the value that i should have:

i = sp - save;  // NB: C pointer subtraction automatically descales

In assembly, this would be subtraction, then right shift by 2 to descale from byte difference value to integer index value.

(Beware, it is easy to be off by one with these optimizations & transformations, so check the work.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM