Meilleur cas 8 cycles, pire cas 12 cycles
Comme ce n'est pas clair dans la question, je fonde cela sur les latences d'Ivy Bridge.
L'approche ici consiste à utiliser l' bsr
instruction (bit scan reverse) comme log2 () du pauvre. Le résultat est utilisé comme index dans une table de sauts qui contient des entrées pour les bits 0 à 42. Je suppose que, étant donné que l'opération sur les données 64 bits est implicitement requise, alors l'utilisation de l' bsr
instruction est OK.
Dans le meilleur des cas, l'entrée jumptable peut mapper le bsr
résultat directement à l'amplitude. Par exemple, pour les entrées dans la plage 32-63, le bsr
résultat sera 5, qui est mappé à une amplitude de 1. Dans ce cas, le chemin d'instruction est:
Instruction Latency
bsrq 3
jmp 2
movl 1
jmp 2
total 8
Dans le pire des cas, les entrées bsr
seront mappées à deux amplitudes possibles, de sorte que l'entrée de saut peut en faire une supplémentaire cmp
pour vérifier si l'entrée est> 10 n . Par exemple, pour les entrées dans la plage 64-127, le bsr
résultat sera 6. L'entrée de pontage correspondante vérifie ensuite si l'entrée> 100 et définit la grandeur de sortie en conséquence.
De plus, pour le pire des cas, nous avons une instruction mov supplémentaire pour charger une valeur immédiate de 64 bits à utiliser dans le cmp
, donc le pire des instructions est:
Instruction Latency
bsrq 3
jmp 2
movabsq 1
cmpq 1
ja 2
movl 1
jmp 2
total 12
Voici le code:
/* Input is loaded in %rdi */
bsrq %rdi, %rax
jmp *jumptable(,%rax,8)
.m0:
movl $0, %ecx
jmp .end
.m0_1:
cmpq $9, %rdi
ja .m1
movl $0, %ecx
jmp .end
.m1:
movl $1, %ecx
jmp .end
.m1_2:
cmpq $99, %rdi
ja .m2
movl $1, %ecx
jmp .end
.m2:
movl $2, %ecx
jmp .end
.m2_3:
cmpq $999, %rdi
ja .m3
movl $2, %ecx
jmp .end
.m3:
movl $3, %ecx
jmp .end
.m3_4:
cmpq $9999, %rdi
ja .m4
movl $3, %ecx
jmp .end
.m4:
movl $4, %ecx
jmp .end
.m4_5:
cmpq $99999, %rdi
ja .m5
movl $4, %ecx
jmp .end
.m5:
movl $5, %ecx
jmp .end
.m5_6:
cmpq $999999, %rdi
ja .m6
movl $5, %ecx
jmp .end
.m6:
movl $6, %ecx
jmp .end
.m6_7:
cmpq $9999999, %rdi
ja .m7
movl $6, %ecx
jmp .end
.m7:
movl $7, %ecx
jmp .end
.m7_8:
cmpq $99999999, %rdi
ja .m8
movl $7, %ecx
jmp .end
.m8:
movl $8, %ecx
jmp .end
.m8_9:
cmpq $999999999, %rdi
ja .m9
movl $8, %ecx
jmp .end
.m9:
movl $9, %ecx
jmp .end
.m9_10:
movabsq $9999999999, %rax
cmpq %rax, %rdi
ja .m10
movl $9, %ecx
jmp .end
.m10:
movl $10, %ecx
jmp .end
.m10_11:
movabsq $99999999999, %rax
cmpq %rax, %rdi
ja .m11
movl $10, %ecx
jmp .end
.m11:
movl $11, %ecx
jmp .end
.m11_12:
movabsq $999999999999, %rax
cmpq %rax, %rdi
ja .m12
movl $11, %ecx
jmp .end
.m12:
movl $12, %ecx
jmp .end
jumptable:
.quad .m0
.quad .m0
.quad .m0
.quad .m0_1
.quad .m1
.quad .m1
.quad .m1_2
.quad .m2
.quad .m2
.quad .m2_3
.quad .m3
.quad .m3
.quad .m3
.quad .m3_4
.quad .m4
.quad .m4
.quad .m4_5
.quad .m5
.quad .m5
.quad .m5_6
.quad .m6
.quad .m6
.quad .m6
.quad .m6_7
.quad .m7
.quad .m7
.quad .m7_8
.quad .m8
.quad .m8
.quad .m8_9
.quad .m9
.quad .m9
.quad .m9
.quad .m9_10
.quad .m10
.quad .m10
.quad .m10_11
.quad .m11
.quad .m11
.quad .m11_12
.quad .m12
.quad .m12
.quad .m12
.end:
/* output is given in %ecx */
Cela a été principalement généré à partir de la sortie de l'assembleur gcc pour le code C de preuve de concept que j'ai écrit . Notez que le code C utilise un goto calculable pour implémenter la table de saut. Il utilise également la fonction __builtin_clzll()
intégrée gcc, qui compile l' bsr
instruction (plus un xor
).
J'ai envisagé plusieurs solutions avant d'arriver à celle-ci:
FYL2X
pour calculer le logarithme naturel, puis FMUL
par la constante nécessaire. Ce serait probablement gagner si c'était un concours [tag: instruction: golf]. Mais FYL2X
a une latence de 90-106 pour Ivy bridge.
Recherche binaire codée en dur. Cela peut en fait être compétitif - je laisse le soin à quelqu'un d'autre de l'implémenter :).
Tableau de recherche complet des résultats. Je suis sûr que cela est théoriquement le plus rapide, mais nécessiterait une table de recherche de 1 To - pas encore pratique - peut-être dans quelques années si la loi de Moore continue de tenir.