EC

  • Edwin Chan
  • CV
  • CPSC 233
  • CPSC 331
  • CPSC 355
  • CPSC 581
  • Origami
  • Random

[Example] While (pre-test) loop in Assembly

A While loop is a pre-test loop, because you test the condition before the first iteration. This is compared to something like a Do-While loop, which executes at least one iteration before testing the condition (post-test).

Compare the unoptimized vs optimized versions. When unoptimized, all three highlighted lines are inside the loop, so (3 lines * 10 loop iterations) = 30 instructions. When optimized, one of the highlighted lines is moved outside the loop and only executed once, so (2 lines * 10 loop interations) + 1 = 21 instructions.

While Loop (unoptimized)

// Program to show how to use a while-loop.
// Loops 10 times, prints the loop # each iteration.

// Define format string for call to printf()
fmt: .string "Loop: %d\n"

      // Define the main function for our program
      .balign 4                    // Instructions must be word aligned
      .global main                 // Make "main" visible to the OS
main: stp x29, x30, [sp, -16]!     // Save frame pointer (fp, x29) and link register (lr, x30) to stack, allocating 16 bytes, pre-increment SP
      mov x29, sp                  // Update frame pointer (fp) to current stack pointer (sp) (after we've incremented sp in the last step)

      mov x19, 0                   // Set x19 general purpose register to 0, this will be the loop counter

      // While loop (pre-test, so check before the first iteration)
      // Let's loop 10 times, printing out each number.
test: cmp  x19, 10                 // Compare loop counter and 10
      b.ge done                    // If [loop counter]>=10, exit loop and branch to "done"

      // Start of code inside the loop
      adrp x0, fmt                 // Set the 1st argument of printf(fmt, var1, var2...) (high-order bits)
      add  x0, x0, :lo12:fmt       // Set the 1st argument of printf(fmt, var1, var2...) (lower 12 bits)
      add  x1, x19, 1              // Set the 2nd argument of printf().
                                   // We are adding one, then saving it to x1 register as 2nd argument
                                   // This is just to print 1-10, instead of 0-9
      bl   printf // Call the printf() function
      // End of code inside the loop

      add  x19, x19, 1             // Increment loop counter by 1
      b    test                    // Loop iteration has ended, goto test to see if we should execute loop again

      // Return 0 in main, like we did in C
done: mov  w0, 0

      // Restore registers and return to calling code (OS)
      ldp  x29, x30, [sp], 16      // Restore fp and lr from stack, post-increment sp
      ret                          // Return to caller

While Loop (optimized) (this is an m4 file, you have to use m4 command to convert to .s assembly file)

// Shows how to optimize the whileloop.s code.
// Loops ten times, prints the loop # each iteration.
// Uses M4 macros, places loop at end of pre-test loop (to save one instruction)
// Don't forget to optimize your assignment with instructions like madd or msub

// Define M4 macros
define(loop_r, x19) // loop counter register
define(fp, x29)     // frame pointer
define(lr, x30)     // link register

// Define format string for call to printf()
fmt: .string "Loop: %d\n"

      // Define the main function for our program
      .balign 4                        // Instructions must be word aligned
      .global main                     // Make "main" visible to the OS
main: stp  fp, lr, [sp, -16]!          // Save frame pointer (fp, x29) and link register (lr, x30) to stack, allocating 16 bytes, pre-increment SP
      mov  fp, sp                      // Update frame pointer (fp) to current stack pointer (sp) (after we've incremented sp in the last step)

      mov  loop_r, 0                   // Set x19 general purpose register to 0, this will be the loop counter

      // Optimized While loop (pre-test, so check before the first iteration)
      // By placing the test at the bottom, we save one instruction
      // Let's loop 10 times, printing out each number.

      b test                           // Branch to loop test at bottom
                                       // NOTICE how this branch instruction only happens ONCE, OUTSIDE THE LOOP.
                                       // In the unoptimized version, this instruction is executed in every iteration.
                                       // Even though the test code is below the loop code, this is still a pre-test loop
                                       // because we branch directly to the loop, before executing the loop (if the loop
                                       // condition is satisfied).

top:  // Start of code inside the loop
      adrp x0, fmt                     // Set the 1st argument of printf(fmt, var1, var2...) (high-order bits)
      add  x0, x0, :lo12:fmt           // Set the 1st argument of printf(fmt, var1, var2...) (lower 12 bits)
      add  x1, loop_r, 1               // Set the 2nd argument of printf().
                                       // We are adding one, then saving it to x1 register as 2nd argument
                                       // This is just to print 1-10, instead of 0-9
      bl   printf                      // Call the printf() function
      // End of code inside the loop

      add  loop_r, loop_r, 1           // Increment loop counter by 1

      // Loop test
test: cmp  loop_r, 10                  // Compare loop counter and 10
      b.lt top                         // If [loop counter]>=10, exit loop and branch to "done"

      // Return 0 in main, like we did in C
done: mov  w0, 0

      // Restore registers and return to calling code (OS)
      ldp  fp, lr, [sp], 16            // Restore fp and lr from stack, post-increment sp
      ret                              // Return to caller

  • Edwin Chan
  • CV
  • CPSC 233
  • CPSC 331
  • CPSC 355
  • CPSC 581
  • Origami
  • Random