un compilateur ne sait pas si ta boucle est faite 10,100,10 000 fois.
D'ailleurs son code C est tronqué ,quand il deplit il fait 8 fois, mais le compilateur comment il sait qu'il peut déplier 8 fois ?
Beh si, il sait justement. Le loop unrolling, c'est pas fait sur le compteur de boucle for i = O; i < N; i++), mais sur le nombre d'ALU disponible sur le CPU, on le nombre d'exécution qui peuvent se faire en parallèle (SIMD). À la limite, il peut aussi déplier sur la taille du cache et du prefetcher (si la boucle touche une zone de 16 octets, il va déplier suffisamment pour les 4 itérations rentrent dans une ligne de caches de 64 octets).
De toute façon, le compilateur va convertir ton code en une sorte d'arbre logique des opérations à effectuer sur les données, et le backend va essayer de mapper ces opérations le mieux possible sur l'architecture binaire cible. Et le gros problème, c'est justement de décrire cette architecture cible en étant le plus efficace (et juste!) possible.
L'itanium est arrivé trop tôt et le soft était pas prêt à utiliser cette architecture. Les algorithmes SIMD/vectorisés sont arrivés des années plus tard.
De plus, c'est quasi impossible de faire un processeur efficace avec de multiples instructions/cycle sans avoir de out of order ou au moins une sorte de microcode. Les dépendances sont simplement insolvables sans résoudre l'ordre d'accès aux données (sequential memory access synchronization) sur un vecteur de plusieurs opérations, ce que le compilateur ne fourni pas (sauf en C++ pour les atomiques, mais c'est tout).
Donc, au niveau du processeur, si tu as la séquence de code:
A = B
B++
C = D
D = B
A += C
Bien que toutes ces opérations soient indépendantes les unes des autres (sauf la dernière), le processeur ne peut pas faire A = B en même temps que B++ car l'accès et le stockage à B doit être synchronisé sur ses ALU. Avec le OutOfOrder, il peut réordonner (A=B, C=D) et (B++, D=B) s'il le veut et s'affranchir de la synchronisation des caches pour saturer ses unités d'exécution.
Le compilateur ne peut pas changer l'ordre non plus (à la limite le C=D peut remonter) car le D=B a un effet observable donc B doit être calculé. Je ne parle même pas des atomiques/volatiles.
Ici avec 2 unités d'exécutions, tu ne peux pas faire moins que 4 cycles (A = B, puis B++, puis (C=D, D=B), puis A+=C) sans OoO, vue les dépendances.
Je parle ici de l'aspect implémentation et pas mathématique évidemment.
[^] # Re: Ok, le hardware pourrait être fait, mais le software ?
Posté par xryl669 . En réponse à la dépêche AltairX : le processeur du futur ?. Évalué à 2.
Beh si, il sait justement. Le loop unrolling, c'est pas fait sur le compteur de boucle
for i = O; i < N; i++), mais sur le nombre d'ALU disponible sur le CPU, on le nombre d'exécution qui peuvent se faire en parallèle (SIMD). À la limite, il peut aussi déplier sur la taille du cache et du prefetcher (si la boucle touche une zone de 16 octets, il va déplier suffisamment pour les 4 itérations rentrent dans une ligne de caches de 64 octets).De toute façon, le compilateur va convertir ton code en une sorte d'arbre logique des opérations à effectuer sur les données, et le backend va essayer de mapper ces opérations le mieux possible sur l'architecture binaire cible. Et le gros problème, c'est justement de décrire cette architecture cible en étant le plus efficace (et juste!) possible.
L'itanium est arrivé trop tôt et le soft était pas prêt à utiliser cette architecture. Les algorithmes SIMD/vectorisés sont arrivés des années plus tard.
De plus, c'est quasi impossible de faire un processeur efficace avec de multiples instructions/cycle sans avoir de out of order ou au moins une sorte de microcode. Les dépendances sont simplement insolvables sans résoudre l'ordre d'accès aux données (sequential memory access synchronization) sur un vecteur de plusieurs opérations, ce que le compilateur ne fourni pas (sauf en C++ pour les atomiques, mais c'est tout).
Donc, au niveau du processeur, si tu as la séquence de code:
A = B
B++
C = D
D = B
A += C
Bien que toutes ces opérations soient indépendantes les unes des autres (sauf la dernière), le processeur ne peut pas faire A = B en même temps que B++ car l'accès et le stockage à B doit être synchronisé sur ses ALU. Avec le OutOfOrder, il peut réordonner (A=B, C=D) et (B++, D=B) s'il le veut et s'affranchir de la synchronisation des caches pour saturer ses unités d'exécution.
Le compilateur ne peut pas changer l'ordre non plus (à la limite le C=D peut remonter) car le D=B a un effet observable donc B doit être calculé. Je ne parle même pas des atomiques/volatiles.
Ici avec 2 unités d'exécutions, tu ne peux pas faire moins que 4 cycles (A = B, puis B++, puis (C=D, D=B), puis A+=C) sans OoO, vue les dépendances.
Je parle ici de l'aspect implémentation et pas mathématique évidemment.