Pollux (./106) :
Si il avait envie de déléguer la génération de code le plus simple serait plutôt de transformer son code en code C
C'est de la bidouille, ça.
Il y a 2 manières de s'y prendre, les deux ont des problèmes:
* conversion haut-niveau, où le code reste reconnaissable dans la version C:
- impose un langage très proche du C (=> Où est l'intérêt d'un tel langage?)
- délègue une partie de la vérification sémantique (et éventuellement même syntaxique) au compilateur C, donc les messages d'erreur sont moins clairs (parce qu'ils portent sur du code déjà prétraîté)
* conversion bas-niveau, où le C est utilisé comme un "assembleur portable":
- donne du code C illisible, donc difficile à déboguer
- utilise le C comme un langage intermédiaire, ce qui n'est pas idéal (par exemple, on n'a pas accès aux caractéristiques du target à moins de dupliquer les informations que GCC a dans le convertisseur frontend)
- donne à GCC du code qui a déjà perdu de l'information, par exemple GCC ne voit plus les boucles, donc il ne peut pas faire des optimisations de boucles là-dessus!
Et dans les 2 cas, des concepts qui peuvent être exprimés en assembleur, mais difficilement en C, sont forcément implémentés soit de manière très inefficace, soit pas du tout.
Sinon je ne comprends pas pourquoi tu dis que l'allocation de registres n'est pas une optimisation... C'est une optimisation comme les autres, elle transforme un code où les variables sont toutes sur la pile en un code où les variables sont placées au mieux dans les registres 
Dans GCC, elle transforme des pseudo-registres en registres ou en stack slots. Donc c'est une transformation obligatoire.