Aller au contenu principal

Génération de code

Progression

#Génération de code

À quoi ça sert ?

À quoi ça sert: transformer l’AST en une représentation exécutable (bytecode, WASM, assembleur) correcte et efficace. Comment: sélection d’instructions, gestion de la pile et des registres, conventions d’appel, et mapping mémoire des variables.

#À partir de l'AST

L'AST représente la structure du programme de manière hiérarchique. La génération de code consiste à parcourir cet arbre et à produire les instructions correspondantes dans le langage cible.

#Exemple d'AST

Considérons l'expression arithmétique 2 * (3 + 4). L'AST pourrait ressembler à :

bg-[rgba(var(--code-inline-bg),0.5)] text-[rgb(var(--fg))] px-1 roundedbg-[rgba(var(--code-inline-bg),0.5)] text-[rgb(var(--fg))] px-1 rounded
1    *2   / \3  2   +4     / \5    3   4

#Génération de bytecode WASM

WebAssembly (WASM) est un format binaire exécutable dans les navigateurs. Nous allons générer un module WASM simple qui effectue une addition.

#Exemple (Python)

Nous allons créer un générateur de code qui produit un module WASM pour une fonction add(a, b).

pythonpython
1# Simulateur de génération de code WASM2# AST pour add(a, b) = a + b3ast = ('+', ('var', 'a'), ('var', 'b'))4 5# Génération de bytecode WASM (simplifiée)6def codegen_wasm(ast):7    code = []8    if ast[0] == '+':9        # Charger les variables 'a' et 'b' sur la pile10        code.append("local.get $a")11        code.append("local.get $b")12        # Additionner13        code.append("i32.add")14    elif ast[0] == 'var':
Chargement de l’éditeur...

#Structure d'un module WASM

Un module WASM typique contient :

  • Types : Signatures des fonctions.
  • Fonctions : Définitions des fonctions.
  • Exports : Fonctions accessibles depuis l'extérieur.
  • Code : Instructions des fonctions.

#Exemple de module WASM (texte)

watwat
1(module2  (func $add (param $a i32) (param $b i32) (result i32)3    local.get $a4    local.get $b5    i32.add)6  (export "add" (func $add))7)

Ce module définit une fonction add qui prend deux paramètres 32 bits et retourne leur somme.

#IR intermédiaire (LLVM IR)

Dans des compilateurs plus complexes, une IR comme LLVM IR est utilisée pour optimiser le code avant la génération finale.

#Exemple LLVM IR

llvmllvm
1define i32 @add(i32 %a, i32 %b) {2  %result = add i32 %a, %b3  ret i32 %result4}

#Exercice : Générateur de code pour la multiplication

Implémentez un générateur de code qui produit un module WASM pour une fonction mul(a, b) qui multiplie deux entiers.

#Instructions

  1. Définissez un AST pour l'expression a * b.
  2. Implémentez une fonction codegen_wasm qui parcourt l'AST et génère les instructions WASM correspondantes.
  3. Le module WASM doit exporter une fonction mul qui prend deux paramètres i32 et retourne leur produit.

#Exemple de code

pythonpython
1# Simulateur de génération de code WASM2# AST pour mul(a, b) = a * b3ast = ('*', ('var', 'a'), ('var', 'b'))4 5# Génération de bytecode WASM (simplifiée)6def codegen_wasm(ast):7    code = []8    if ast[0] == '*':9        # Charger les variables 'a' et 'b' sur la pile10        code.append("local.get $a")11        code.append("local.get $b")12        # Multiplier13        code.append("i32.mul")14    elif ast[0] == 'var':
Chargement de l’éditeur...
Optimisations
  • Constant Folding : Évaluer les expressions constantes à la compilation.
  • Dead Code Elimination : Supprimer le code non utilisé.
  • Register Allocation : Assigner les variables aux registres du processeur.