Saturday, 21 January 2017

Using the count register


The count register is a special-purpose register used for a loop counter. The BO operand of the conditional branch (controlling the mode) can be used, in addition to specifying how to test condition register bits, to decrement and test the count register. There are two operations you can do with the count register:
  • decrement the count register and branch if it becomes zero
  • decrement the count register and branch if it becomes nonzero
These count register operations can either be used on their own or in conjunction with a condition register test.
In the extended mnemonics, the count register semantics are specified by adding either dz or dnz immediately after the b. Any additional condition or instruction modifier is added after that. So, to have a loop repeat 100 times, you would load the count register with the number 100, and use bdnz to control the loop. Here is how the code would look:
Listing 6. Counter-controlled loop example
#The count register has to be loaded through a general-purpose register
#Load register 31 with the number 100
li 31, 100
#Move it to the count register
mtctr 31

#Loop start address
loop_start:

###loop body goes here###

#Decrement count register and branch if it becomes nonzero
bdnz loop_start

#Code after loop goes here
You can also combine the counter test with other tests. For instance, a loop might need to have an early exit condition. The following code demonstrates an early exit condition when register 24 is equal to register 28.
Listing 7. Count register combined branch example
#The count register has to be loaded through a general-purpose register
#Load register 31 with the number 100
li 31, 100
#Move it to the count register
mtctr 31

#Loop start address
loop_start:

###loop body goes here###

#Check for early exit condition (reg 24 == reg 28)
cmpd 24, 28

#Decrement and branch if not zero, and also test for early exit condition
bdnzf eq, loop_start

#Code after loop goes here
So, rather than having to add an additional conditional branch instruction, all that is needed is the comparison instruction, and the conditional branch is merged into the loop counter branch.

Putting it together

Now we will put this information to practical use.
The first program will be a rewrite of the maximum value program we entered in the first article, and rewrite it according to what we have learned. The first version used a register to hold the current address being read from, and the code used indirect addressing to load the value. What this program will do is use an indexed-indirect addressing mode, with a register for the base address and a register for the index. In addition, rather than the index starting at zero and going forward, the index will count from the end to the beginning in order to save an extra compare instruction. The decrement can implicitly set the condition register (as opposed to an explicit compare with zero), which can then be used by a conditional branch instruction. Here is the new version (enter as max_enhanced.s):
Listing 8. Maximum value program enhanced version
###PROGRAM DATA###
.data
.align 3

value_list:
   .quad 23, 50, 95, 96, 37, 85
value_list_end:

#Compute a constant holding the size of the list
.equ value_list_size, value_list_end - value_list

###ENTRY POINT DECLARATION###
.section .opd, "aw"
.global _start
.align 3
_start:
   .quad ._start, .TOC.@tocbase, 0


###CODE###
._start:   
   .equ DATA_SIZE, 8

   #REGISTER USAGE
   #Register 3 -- current maximum
   #Register 4 -- list address
   #Register 5 -- current index
   #Register 6 -- current value
   #Register 7 -- size of data (negative)

   #Load the address of the list
   ld 4, value_list@got(2)
   #Register 7 has data size (negative)
   li 7, -DATA_SIZE
   #Load the size of the list
   li 5, value_list_size
   #Set the "current maximum" to 0
   li 3, 0
   
loop:
   #Decrement index to the next value; set status register (in cr0)
   add. 5, 5, 7

   #Load value (X-Form - add register 4 + register 5 for final address)
   ldx 6, 4, 5

   #Unsigned comparison of current value to current maximum (use cr2)
   cmpld cr2, 6, 3

   #If the current one is greater, set it (sets the link register)
   btl 4*cr2+gt, set_new_maximum 

   #Loop unless the last index decrement resulted in zero
   bf eq, loop

   #AFTER THE LOOP -- exit
   li 0, 1
   sc

set_new_maximum:
   mr 3, 6
   blr (return using the link register)
Assemble, link, and execute as before:
as -a64 max_enhanced.s -o max_enhanced.o
ld -melf64ppc max_enhanced.o -o max_enhanced
./max_enhanced
The loop in this program is approximately 15% faster than the loop in the first article because (a) we've shaved off several instructions from the main loop by using the status register to detect the end of the list when we decrement register 5 and (b) the program is using different condition register fields for the comparison (so that the result of the decrement can be held for later).
Note that using the link register in the call to set_new_maximum is not strictly necessary. It would have worked just as well to set the return address explicitly rather than using the link register. However, this gives a good example of link register usage.

No comments:

Post a Comment