5.4. Array Loop Shifted Index¶
The loop shown on the last page to loop over an array of words works fine, but uses a lot of registers for book keeping. We use one register for the base address of the array, another for the index of the array (to test when we are done), and another to keep track of the memory offset.
But, the index and offset are redundant. For word index 0 the offset will always be 0, for word index 1 the offset will be 4, for index 2 the offset will be 8,… The offset is always 4x the index.
The ARM instruction set provides a trick to avoid storing the index and 4x the index. When we go to use the index of an array to load data, we can shift it 2 bits. This effectively multiplies it by 4, turning the value 0 into 0, 1 into 4, 2 into 8, etc…
LDR
rd, [rn, rm, lsl #]Access the memory at the byte address rn + (rm shifted left # bits), and store its value into rd. Typically, we will use a shift of 2 to multiply rm by 4. Similar [rn, rm, lsl #] syntax is available for STR.
This code sample below demonstrates looping through an array using this technique. It copies data from myArray to the empty space at doubled and doubles each element of the array as it copies it. It is roughly equivalent to:
int myArraySize = 5;
int myArray[5] = {10, 20, 30, 40, 50};
int doubled[5];
int i = 0;
while(i < myArraySize) {
doubled[i] = 2 * myArray[i];
i++;
}
In the assembly version, we hold the base address of the original array in r2
and the
address of doubled in r3
. r4
is the index - to use it to find the offset of an element in an array
we shift it left 2 bits.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | .data
@An array of 5 ints
myArray: .word 10, 20, 30, 40, 50
arraySize: .word 5 @size of myArray
doubled: .space 20 @20 bytes = 5 words
.text
_start:
LDR r1, =arraySize @ r1 = &arraySize
LDR r1, [r1] @ r1 = arraySize
LDR r2, =myArray @ load myArray start address
LDR r3, =doubled @ load newArray start address
MOV r4, #0 @ r4 = loop counter
B looptest @ jump ahead to loop test
loopstart:
@myArray[i]'s address is r2 + (4 * r4)
LDR r5, [r2, r4, lsl #2] @ r5 = myArray[i]
LSL r5, r5, #1 @double r5
@doubled[i]'s address is r3 + (4 * r4)
STR r5, [r3, r4, lsl #2] @ doubled[i] = r5
@go to next step
ADD r4, r4, #1 @ add one to counter
looptest:
CMP r4, r1 @ Compare counter r4 to size of array in r1
BLT loopstart @ If counter Less Than size, go back to start
end:
B end @stop here
|