Je suis plutôt face à un problème particulier. Je suis en train de travailler sur un compilateur pour une architecture qui ne prend pas en charge les opérations bit à bit. Cependant, il gère signé de 16 bits en entier de l'arithmétique et je me demandais si il serait possible de mettre en œuvre des opérations bit à bit en utilisant uniquement:
- Outre (c = a + b)
- La soustraction (c = a - b)
- Division (c = a / b)
- La Multiplication (c = a * b)
- Module (c = a % b)
- Minimum (c = min(a, b))
- Maximum (c = max(a, b))
- Les comparaisons (c = (a < b), c = (a == b), c = (a <= b), et.c.)
- Sauts (goto, de, he.c.)
Les opérations bit à bit je veux être en mesure de soutien sont:
- Ou (c = a | b)
- Et (c = a & b)
- Xor (c = a ^ b)
- Décalage à gauche (c = a << b)
-
Décalage à droite (c = a >> b)
- (Tous les nombres entiers sont signés, donc c'est un problème)
- Signé Maj (c = a >>> b)
-
Complément (a = ~b)
- (Déjà trouvé une solution, voir ci-dessous)
Normalement le problème est dans l'autre sens; comment obtenir de l'arithmétique des optimisations au niveau du bit à l'aide de hacks. Cependant pas dans ce cas.
Écriture de la mémoire est très rare sur cette architecture, d'où la nécessité pour les opérations bit à bit. Les fonctions au niveau du bit eux-mêmes ne devraient pas utiliser beaucoup de variables temporaires. Cependant, la constante de données en lecture seule & l'instruction de la mémoire est abondante. Une note de côté ici aussi c'est que les sauts et les branches ne sont pas cher et toutes les données sont facilement mis en cache. Sauts coût de la moitié des cycles que l'arithmétique (y compris les load/store) instructions de le faire. En d'autres termes, toutes ces fonctions prises en charge des coûts deux fois les cycles d'un seul saut.
Quelques idées qui pourraient vous aider:
J'ai compris que vous pouvez faire un complément (négation bits) avec le code suivant:
// Bitwise one's complement
b = ~a;
// Arithmetic one's complement
b = -1 - a;
Je me souviens aussi de l'ancienne maj hack lors de la division avec une puissance de deux de sorte que le bit à bit shift peut être exprimé comme:
// Bitwise left shift
b = a << 4;
// Arithmetic left shift
b = a * 16; // 2^4 = 16
// Signed right shift
b = a >>> 4;
// Arithmetic right shift
b = a / 16;
Pour le reste des opérations bit à bit, je suis un peu paumé. Je souhaite que les architectes de cette architecture ont fourni peu d'opérations.
Je voudrais aussi savoir si il est rapide/moyen facile de calculer la puissance de deux (pour les opérations de déplacement) sans l'aide d'une mémoire de données de la table. Un naïf solution serait de sauter dans un champ de multiplications:
b = 1;
switch (a)
{
case 15: b = b * 2;
case 14: b = b * 2;
// ... exploting fallthrough (instruction memory is magnitudes larger)
case 2: b = b * 2;
case 1: b = b * 2;
}
Ou d'un Ensemble & Jump approche:
switch (a)
{
case 15: b = 32768; break;
case 14: b = 16384; break;
// ... exploiting the fact that a jump is faster than one additional mul
// at the cost of doubling the instruction memory footprint.
case 2: b = 4; break;
case 1: b = 2; break;
}