BRAS de montage: auto-incrément de vous inscrire sur la boutique
Est-il possible de l'auto-incrémentation de l'adresse de base d'un registre sur un STR avec un [Rn]!
? J'ai regardé à travers la documentation, mais qui n'ont pas été en mesure de trouver une réponse définitive, principalement parce que la syntaxe de la commande est présentée pour les deux LDR et STR - en théorie, il devrait fonctionner pour les deux, mais je ne pouvais pas trouver des exemples d'auto-incrémentation sur un magasin (le chargement fonctionne ok).
J'ai fait un petit programme qui stocke deux nombres dans un vecteur. Quand c'est fait, le contenu de out
devrait être {1, 2}
, mais le magasin remplace le premier octet, comme si l'incrémentation automatique ne fonctionne pas.
#include <stdio.h>
int main()
{
int out[]={0, 0};
asm volatile (
"mov r0, #1 \n\t"
"str r0, [%0]! \n\t"
"add r0, r0, #1 \n\t"
"str r0, [%0] \n\t"
:: "r"(out)
: "r0" );
printf("%d %d\n", out[0], out[1]);
return 0;
}
EDIT:
Alors que la réponse était la bonne pour des chargements et des magasins, j'ai trouvé que l'optimiseur bousille l'auto-incrémentation sur le vecteur des instructions comme vldm/vstm. Par exemple, le programme suivant
#include <stdio.h>
int main()
{
volatile int *in = new int[16];
volatile int *out = new int[16];
for (int i=0;i<16;i++) in[i] = i;
asm volatile (
"vldm %0!, {d0-d3} \n\t"
"vldm %0, {d4-d7} \n\t"
"vstm %1!, {d0-d3} \n\t"
"vstm %1, {d4-d7} \n\t"
:: "r"(in), "r"(out)
: "memory" );
for (int i=0;i<16;i++) printf("%d\n", out[i]);
return 0;
}
compilé avec
g++ -O2 -march=armv7-a -mfpu=neon main.cpp -o main
produira charabia sur la sortie de la dernière 8 variables, car l'optimiseur est de garder la variable incrémentée et de l'utiliser pour le printf. En d'autres termes, out[i]
est en fait out[i+8]
, de sorte que les 8 premières valeurs imprimées sont les 8 derniers à partir du vecteur et le repos sont des emplacements de mémoire en dehors des limites.
J'ai essayé avec différentes combinaisons de la volatile
mot-clé dans tout le code, mais les changements de comportement que si je compile avec le -O0
drapeau ou si j'utilise un volatile vecteur au lieu d'un pointeur et de nouveau, comme
volatile int out[16];
- diapositive 44, je pense qu'il peut mais Pas moyen de tester en ce moment.. simplemachines.il/doc/arm_inst.pdf utilisation de la ! opérateur
Vous devez vous connecter pour publier un commentaire.
Pour stocker et charger vous faites cela:
ce que vous mettez à la fin, 4 dans ce cas, est ajouté à la base de registre (r1 dans le ldr exemple et r2 dans la str exemple), d'après le registre est utilisé pour l'adresse, mais avant que l'instruction est terminée, il est très bien comme
MODIFIER, vous avez besoin de regarder le niveau de démontage pour voir ce qui se passe, si quoi que ce soit. Je suis à l'aide de la dernière version du code sourcery ou maintenant juste sourcery lite, de mentor graphics suite d'outils.
arm-none-linux-gnueabi-gcc (Sourcery CodeBench Lite 2011.09-70) 4.6.1
de sorte que le
est de répartir les deux ints out[0] et le[1]
est parce qu'ils sont initialisées à zéro, puis vient la ligne d'assemblage
et puis le printf:
et maintenant, il est clair pourquoi il n'a pas fonctionné. vous navez pas déclarer comme volatile. Vous a donné le code aucune raison d'aller vers la ram) pour obtenir les valeurs de[0] et le[1] pour le printf, le compilateur sait que r4 contient la valeur pour les deux out[0] et le[1], il y a tellement peu de code dans cette fonction qu'il n'a pas eu d'expulser r4 et la réutilisation de sorte qu'il a utilisé r4 pour le printf.
Si vous la changez pour être volatile
Alors vous devriez obtenir le résultat souhaité:
la préparation pour printf lit à partir de la ram.
GCC assembleur en ligne exige que tous les registres modifiés et non-volatiles sont répertoriées comme des sorties ou clobbers. Dans le deuxième exemple GCC peut et ne suppose que les registres alloués à
in
etout
ne changent pas.Une approche correcte serait:
J'ai trouvé cette question lors de la recherche de la réponse à une question similaire: Comment lier une entrée/sortie registre. La GCC de la documentation de l'assembleur en ligne constrants dit que le
+
préfixe dans le registre d'entrée de la liste désigne une entrée/sortie registre.Dans l'exemple, il me semble que vous préférez afin de préserver la valeur d'origine de la variable
out
. Néanmoins, si vous souhaitez utiliser la post-incrémentation (!
) variante de la notice, je pense que vous devez déclarer les paramètres en lecture/écriture. La suite travaillé sur mon Raspberry Pi 2:De cette façon, la sémantique du code est clair pour le compilateur: le
in
etout
pointeurs sera changé (incrémenté par 8 éléments).Avertissement: je ne sais pas si le BRAS ABI permet une fonction librement tabasser le NÉON registres d0 grâce à d7. Dans cet exemple simple, il n'a probablement pas d'importance.