Vecteurs : indexation par position

Vecteurs : indexation par position

Un vecteur est un tableau : une séquence de nombres stockés les uns à côté des autres en mémoire. Dans la leçon précédente, vous en avez fait la somme en déplaçant un pointeur de 4 octets pour chaque élément. Cette même méthode fonctionne ici. Il existe une autre façon courante d'atteindre un élément : par index. Un index est la position d'un élément comptée depuis le début, où le premier élément a l'index 0, le deuxième a l'index 1, et ainsi de suite.

Somme d'un vecteur en parcourant un pointeur

Somme d'un vecteur en avançant un pointeur
.data
a: .word 5, 10, 15, 20 # quatre éléments
.text
la t0, a # t0 = adresse de a
li t1, 4 # t1 = nombre d'éléments restants
li t2, 0 # t2 = somme courante
loop:
beq t1, zero, done
lw t3, 0(t0) # charge l'élément courant
add t2, t2, t3 # ajoute au total
addi t0, t0, 4 # avance au mot suivant (4 octets)
addi t1, t1, -1 # un de moins
j loop
done:
mv a0, t2 # affiche le total : 5+10+15+20 = 50
li a7, 1
ecall
li a7, 10
ecall

La boucle s'exécute comme suit. t0 contient l'adresse de a, et t1 contient le nombre d'éléments restants, en commençant à 4. À chaque passage, termine la boucle lorsque le compteur atteint zéro. charge l'élément à l'adresse contenue dans t0. ajoute cette valeur au total cumulé. avance le pointeur vers le mot suivant. décrémente le compteur. Après quatre passages (5 + 10 + 15 + 20), done affiche 50. C'est le même schéma que celui utilisé dans la leçon sur la mémoire, désormais appliqué à un vecteur.

De l'index à l'adresse

L'indexation calcule une adresse à partir d'un pointeur de base et d'une position : address = base + index * 4. Le 4 est la taille d'un mot en octets. Un compilateur génère ce même calcul pour a[i] dans un langage tel que le C. L'index lui-même n'accède jamais à la mémoire. Seule l'adresse calculée à partir de lui le fait.

Index vers adresse, à l'aide d'un décalage
slli t5, t3, 2 # t5 = index * 4 (taille d'un mot)
add t6, t0, t5 # t6 = adresse de element[index]
lw t6, 0(t6) # t6 = element[index]

décale l'index dans t3 de 2 bits vers la gauche, ce qui le multiplie par 4 (deux doublements : 2 x 2), la taille d'un mot. Ajouter le résultat au pointeur de base donne l'adresse de element[index]. Ce décalage est la même méthode des puissances de deux que dans la leçon sur l'arithmétique, et c'est la façon standard de mettre un index à l'échelle par la taille d'un mot.

Calcul d'adresse
adresse=base+0×4=base+0
a[0]3
0x10010000
a[1]6
0x10010004
a[2]9
0x10010008
a[3]12
0x1001000c

a[0]: index 0, décalage 0.

La barre de pointeur et le badge hexadécimal se déplacent ensemble tandis que l'index parcourt 0, 1, 2, 3. Ils présentent le même fait sous deux formes : i en tant que position, et l'adresse que cette position produit après que l'a mise à l'échelle par 4 et ajoutée à la base. Les nombres hexadécimaux sont les adresses réelles qu'occupe a lorsque le simulateur exécute ce programme. Le but est de prédire l'adresse suivante avant qu'elle n'apparaisse. Cela vous permet de lire dans une boucle incrémentale, ou a[i] dans un langage de type C, et d'imaginer l'adresse mémoire qu'il touche au lieu de traiter la notation comme une boîte noire.

Sommer un vecteur par index

Somme d'un vecteur en utilisant un index
.data
a: .word 5, 10, 15, 20 # quatre éléments
.text
la t0, a # t0 = adresse de base de a
li t1, 4 # t1 = nombre d'éléments
li t2, 0 # t2 = index, commence à 0
li t3, 0 # t3 = total cumulatif
loop:
beq t2, t1, done
slli t4, t2, 2 # t4 = index * 4 (décalage en octets)
add t5, t0, t4 # t5 = adresse de a[index]
lw t5, 0(t5) # t5 = a[index]
add t3, t3, t5 # total += a[index]
addi t2, t2, 1 # passe à l'index suivant
j loop
done:
mv a0, t3 # affiche le total : 5+10+15+20 = 50
li a7, 1
ecall
li a7, 10
ecall

La boucle s'exécute comme suit. t2 est l'index, commençant à 0. À chaque passage, termine la boucle lorsque l'index atteint 4, le nombre d'éléments contenu dans t1. convertit l'index en décalage en octets. ajoute ce décalage à l'adresse de base dans t0 pour produire l'adresse de a[index]. charge la valeur stockée à cet endroit. Cette valeur est ajoutée au total cumulé dans t3, et passe à l'index suivant. Après quatre passages (5 + 10 + 15 + 20), done affiche 50.

Addition de deux vecteurs, élément par élément

c[i] = a[i] + b[i]
.data
a: .word 3, 6, 9, 12 # premier vecteur
b: .word 1, 2, 3, 4 # second vecteur
c: .space 16 # place pour 4 mots de résultat
.text
la t0, a # adresse de base de a
la t1, b # adresse de base de b
la t2, c # adresse de base de c
li t3, 0 # index, commence à 0
li t4, 4 # nombre d'éléments
li s0, 0 # total courant
loop:
beq t3, t4, done
slli t5, t3, 2 # décalage en octets = index * 4
add t6, t0, t5 # adresse de a[index]
lw t6, 0(t6) # valeur de a[index]
add a0, t1, t5 # adresse de b[index]
lw a0, 0(a0) # valeur de b[index]
add t6, t6, a0 # a[index] + b[index]
add a0, t2, t5 # adresse de c[index]
sw t6, 0(a0) # c[index] = a[index] + b[index]
add s0, s0, t6 # total += c[index]
addi t3, t3, 1 # passe à l'index suivant
j loop
done:
mv a0, s0 # affiche le total : 4+8+12+16 = 40
li a7, 1
ecall
li a7, 10
ecall

La boucle s'exécute comme suit. convertit l'index t3 en décalage en octets. L'ajouter à chaque pointeur de base (t0, t1, t2) donne les adresses de a[i], b[i] et c[i]. À chaque passage, les deux éléments sont chargés, additionnés, stockés dans c, et ajoutés au total cumulé dans s0. passe à l'index suivant, et la boucle se répète jusqu'à ce que les quatre éléments soient traités.

💡
Ce schéma d'index, base + index * taille de l'élément, est la façon dont tout accès à un tableau se compile, dans n'importe quel langage. Gardez-le en tête : la leçon suivante utilise la même idée deux fois à la fois pour atteindre une matrice.