avoir une grammaire ultra-simple sans les constructions minimum n'est pas vraiment aidant question optimisation
Dans le cas particulier où la grammaire du langage L ne permet pas d'exprimer des concepts de plus haut niveau que le langage C, on est d'accord. Mais en règle générale, on n'est pas d'accord: je prétend qu'on peut faire un langage de haut niveau qui compile vers du C et qui tourne plus vite que code C saisi par un humain.
Donc on est bien d'accord :)
Moi je disais juste que c'est dommage de chercher à faire un langage de haut niveau puissant question optimisation si c'est pour produire du C au final : on va comme tu dis perdre un grand nombre de possibilités d'optimisation sur le code final, vu qu'on sera limité au sens du langage C.
Je disais le contraire... Si tu avais raison, ça ne servirait à rien (au niveau des optimisations) de coder dans un langage de haut niveau puisque de toutes façons au final on se retrouve avec du code machine qui manipule des bits.
Je ne peux pas tellement trouver d'exemples plus explicites que ceux de mon précédent message (d'autant plus que ce n'est pas mon domaine). L'idée générale, si on a la chaîne de compilation suivante:
[code en L] --(étape 1)--> [code en C] --(étape 2)--> [code en M] -> (étape 3: exécution)
Admettons qu'on a à faire un programme P, et qu'on le donne à un développeur, qui produit un programme PL en langage L, et à un autre développeur qui produit un programme PC en langage C. Appelons PLC le programme PL compilé vers du C.
Si le langage L permet de manipuler des concepts de plus haut niveau que le langage C, alors le compilateur L peut essayer durant l'étape 1 de faire des optimisations sur PL qui font que PLC compilé en M produira du code plus rapide que PC compilé en M.
Je reprend l'exemple de l'héritage. Soit L un langage objet, et soit c un objet de classe C qui hérite de B qui hérite de A. Quand j'appelle c.toto(), on doit chercher si C implémente toto(), sinon B, sinon A. Une fois qu'on a trouvé toto(), on peut décider soit de faire un appel de fonction, soit d'inliner la fonction si c'est plus efficace.
Si on peut toujours résoudre le problème de trouver la fonction à appeler à l'étape 1, alors on peut produire du code C avec des appels de fonction directs ou bien du code inliné.
Si on essaye de coder la même chose directement en C, étant donné que le C n'a pas de concept d'héritage et que son préprocesseur n'est pas assez puissant, on est obliger de chercher la fonction toto() à l'étape 3 (runtime), ce qui signifie qu'on se traine des pointeurs de fonctions, et qu'on ne peut pas inliner. Autrement dit, si tu veux gérer l'héritage, le problème "trouver toto" doit être résolu à une étape, et le C ne permet pas de le résoudre à l'étape 2. Si tu le résouds à l'étape 3, tu perds en performance. Il ne reste que l'étape 1 pour optimiser.
(Disclaimer: un programmeur peut théoriquement faire le boulot du compilateur L à l'étape 1 et produire lui-même à la main le code C correspondant. De la même manière qu'un programmeur peut théoriquement recoder n'importe quoi entièrement en assembleur. C'est simplement trop compliqué et trop long à faire dans la vraie vie.)
[^] # Re: Comment faire un langage plus rapide que C ?
Posté par Yusei (Mastodon) . En réponse à la dépêche 23 mars: Conférence au LORIA sur Lisaac, un nouveau langage. Évalué à 6.
Dans le cas particulier où la grammaire du langage L ne permet pas d'exprimer des concepts de plus haut niveau que le langage C, on est d'accord. Mais en règle générale, on n'est pas d'accord: je prétend qu'on peut faire un langage de haut niveau qui compile vers du C et qui tourne plus vite que code C saisi par un humain.
Je disais le contraire... Si tu avais raison, ça ne servirait à rien (au niveau des optimisations) de coder dans un langage de haut niveau puisque de toutes façons au final on se retrouve avec du code machine qui manipule des bits.
Je ne peux pas tellement trouver d'exemples plus explicites que ceux de mon précédent message (d'autant plus que ce n'est pas mon domaine). L'idée générale, si on a la chaîne de compilation suivante:
[code en L] --(étape 1)--> [code en C] --(étape 2)--> [code en M] -> (étape 3: exécution)
Admettons qu'on a à faire un programme P, et qu'on le donne à un développeur, qui produit un programme PL en langage L, et à un autre développeur qui produit un programme PC en langage C. Appelons PLC le programme PL compilé vers du C.
Si le langage L permet de manipuler des concepts de plus haut niveau que le langage C, alors le compilateur L peut essayer durant l'étape 1 de faire des optimisations sur PL qui font que PLC compilé en M produira du code plus rapide que PC compilé en M.
Je reprend l'exemple de l'héritage. Soit L un langage objet, et soit c un objet de classe C qui hérite de B qui hérite de A. Quand j'appelle c.toto(), on doit chercher si C implémente toto(), sinon B, sinon A. Une fois qu'on a trouvé toto(), on peut décider soit de faire un appel de fonction, soit d'inliner la fonction si c'est plus efficace.
Si on peut toujours résoudre le problème de trouver la fonction à appeler à l'étape 1, alors on peut produire du code C avec des appels de fonction directs ou bien du code inliné.
Si on essaye de coder la même chose directement en C, étant donné que le C n'a pas de concept d'héritage et que son préprocesseur n'est pas assez puissant, on est obliger de chercher la fonction toto() à l'étape 3 (runtime), ce qui signifie qu'on se traine des pointeurs de fonctions, et qu'on ne peut pas inliner. Autrement dit, si tu veux gérer l'héritage, le problème "trouver toto" doit être résolu à une étape, et le C ne permet pas de le résoudre à l'étape 2. Si tu le résouds à l'étape 3, tu perds en performance. Il ne reste que l'étape 1 pour optimiser.
(Disclaimer: un programmeur peut théoriquement faire le boulot du compilateur L à l'étape 1 et produire lui-même à la main le code C correspondant. De la même manière qu'un programmeur peut théoriquement recoder n'importe quoi entièrement en assembleur. C'est simplement trop compliqué et trop long à faire dans la vraie vie.)