Assembly Language for Beginners

(nextflipdebug2) #1

3.7. LOOPS: SEVERAL ITERATORS


There is nocountervariable any more: GCC concluded that it is not needed.


The last element of thea2array is calculated before the loop begins (which is easy:cnt∗ 7 ) and that’s how
the loop is to be stopped: just iterate until the second index reaches this precalculated value.


You can read more about multiplication using shifts/additions/subtractions here:1.18.1 on page 213.


This code can be rewritten into C/C++ like that:


#include <stdio.h>


void f(int a1, int a2, size_t cnt)
{
size_t idx1=0; idx2=0;
size_t last_idx2=cnt*7;


// copy from one array to another in some weird scheme
for (;;)
{
a1[idx1]=a2[idx2];
idx1+=3;
idx2+=7;
if (idx2==last_idx2)
break;
};
};


GCC (Linaro) 4.9 for ARM64 does the same, but it precalculates the last index ofa1instead ofa2, which,
of course has the same effect:


Listing 3.15: Optimizing GCC (Linaro) 4.9 ARM64

; X0=a1
; X1=a2
; X2=cnt
f:
cbz x2, .L1 ; cnt==0? exit then
; calculate last element of "a1" array
add x2, x2, x2, lsl 1
; X2=X2+X2<<1=X2+X22=X23
mov x3, 0
lsl x2, x2, 2
; X2=X2<<2=X24=X234=X212
.L3:
ldr w4, [x1],28 ; load at X1, add 28 to X1 (post-increment)
str w4, [x0,x3] ; store at X0+X3=a1+X3
add x3, x3, 12 ; shift X3
cmp x3, x2 ; end?
bne .L3
.L1:
ret


GCC 4.4.5 for MIPS does the same:


Listing 3.16: Optimizing GCC 4.4.5 for MIPS (IDA)

; $a0=a1
; $a1=a2
; $a2=cnt
f:
; jump to loop check code:
beqz $a2, locret_24
; initialize counter (i) at 0:
move $v0, $zero ; branch delay slot, NOP


loc_8:
; load 32-bit word at $a1
lw $a3, 0($a1)
; increment counter (i):
addiu $v0, 1
; check for finish (compare "i" in $v0 and "cnt" in $a2):
sltu $v1, $v0, $a2

Free download pdf