Quand une primitive commence par "%" elle n'est pas implémentée en C mais doit être gérée par le "backend". On peut voir la traduction dans la représentation intermédiaire ici: translcore.ml#L293.
Pour le backend bytecode (interpréteur), la compilaton se fera vers un opcode dédié pour les entiers taggés (bytegen.ml#L344), et une fonction C externe pour les autres types entiers (bytegen.ml#L420) de la forme: caml_{nativeint,int32,int64}_shift_{left,right,right_unsigned} (bytegen.ml#L312).
Pour les backend natifs, la procédure est un peu plus longue. D'abord quelques optimisations (constant folding dans closure.ml puis unboxing dans cmmgen.ml. Après ces passes, on a encore un langage indépendant de la plateforme ciblée, CMM et les opérations sont maintenant nommées Clsl, Clsr et Casr (cmm.mli#L115).
Les étapes suivantes vont traduire la primitive vers la ou les instructions appropriées de l'architecture cible: abstraite par Mach.Iasr, implémentée directement par les émetteurs de code (voir Iasr dans arm, arm64, une abstraction de plus pour amd64 et i386).
Et ça peut expliquer pourquoi une sémantique sous-spécifiée a été choisie (mais je spécule) : les shifts sont traduits vers du code très efficace, mais leurs sémantiques côté machine change selon les plateformes. X86 masque les 5 ou 6 derniers bits avant, et donc ça se comporte comme une fonction périodique, ARM sature. Le choix d'OCaml est donc un comportement avec une spécification suffisante mais minimale, et proche de la plateforme pour (le code généré est "prédictible" et efficace). L'utilisateur a toujours la possibilité d'implémenter des fonctions plus fortement spécifiées, le coût ne devrait pas être prohibitif.
[^] # Re: Primitive en C pour OCaml
Posté par Def . En réponse au journal Un décalage de 64 bits, ça vous inspire comment ?. Évalué à 9.
Quand une primitive commence par "%" elle n'est pas implémentée en C mais doit être gérée par le "backend". On peut voir la traduction dans la représentation intermédiaire ici: translcore.ml#L293.
Pour le backend bytecode (interpréteur), la compilaton se fera vers un opcode dédié pour les entiers taggés (bytegen.ml#L344), et une fonction C externe pour les autres types entiers (bytegen.ml#L420) de la forme:
caml_{nativeint,int32,int64}_shift_{left,right,right_unsigned}(bytegen.ml#L312).Pour les backend natifs, la procédure est un peu plus longue. D'abord quelques optimisations (constant folding dans closure.ml puis unboxing dans cmmgen.ml. Après ces passes, on a encore un langage indépendant de la plateforme ciblée, CMM et les opérations sont maintenant nommées
Clsl,ClsretCasr(cmm.mli#L115).Les étapes suivantes vont traduire la primitive vers la ou les instructions appropriées de l'architecture cible: abstraite par Mach.Iasr, implémentée directement par les émetteurs de code (voir
Iasrdans arm, arm64, une abstraction de plus pouramd64 et i386).
Et ça peut expliquer pourquoi une sémantique sous-spécifiée a été choisie (mais je spécule) : les shifts sont traduits vers du code très efficace, mais leurs sémantiques côté machine change selon les plateformes. X86 masque les 5 ou 6 derniers bits avant, et donc ça se comporte comme une fonction périodique, ARM sature. Le choix d'OCaml est donc un comportement avec une spécification suffisante mais minimale, et proche de la plateforme pour (le code généré est "prédictible" et efficace). L'utilisateur a toujours la possibilité d'implémenter des fonctions plus fortement spécifiées, le coût ne devrait pas être prohibitif.