Postscript, | Luc Maranget | Le poly |
add r1, r2, r3 # r1 ← r2+r3 « trois-adresses » add r1, r2, i16 # r1 ← r2+i16 immédiat |
li r1, i # r1 ← i16 et r1 ← i32 la r1, l # r1 ← l |
sw r1, i16(r2) # [i16+r2] ← r1 lw r1, i16(r2) # r1 ← [i16+r2] |
move r1, r2 # r1 ← r2 |
|
|
|
|
|
|
(* Intervalle [−2b−1… 2b−1[ représentables sur b bits *) let seize_bits i = -(1 lsl 15) <= i && i < (1 lsl 15) let emit s = Printf.printf "%s\n" let rec emit_exp e = match e with | Temp _ -> () (* cas de base, pas d'instruction *) (* Constante entière *) | Const i -> emit "r1 ← i" (* l'assembleur distingue r1 ← i16 et r1 ← i32 *) (* Addition *) | Bin (Plus, Const i, e2) when seize_bits i -> emit_exp e2 ; emit "r1 ← r2 + i16" | Bin (Plus, e1, Const i) when seize_bits i -> emit_exp e1 ; emit "r1 ← r2 + i16" | Bin (Plus, e1, e2) -> emit_exp e1 ; emit_exp e2 ; emit "r1 ← r2 + r3" |
(* Accès mémoire *) | Mem (Bin (Plus, Const i, e2)) when seize_bits i -> emit_exp e2 ; emit "r1 ← [i16 + r2]" | Mem (Bin (Plus, e1, Const i)) when seize_bits i -> emit_exp e1 ; emit "r1 ← [i16 + r2]" | Mem (Bin (Sub , e1, Const i)) when seize_bits (-i) -> emit_exp e1 ; emit "r1 ← [i16 + r2]" (* i16 est -i *) | Mem e -> emit_exp e ; emit "r1 ← [0 + r2]" | ... and emit_stm stm = match stm with ... |
type temp = Gen.temp type label = Gen.label type instr = | Oper of string * temp list * temp list * label list option (* Oper (mnémonique, sources, destinations, sauts) *) | Move of string * temp * temp | Label of string * label |
Oper ("add ^d0, ^s0, ^s1", [t2 ; t3], [t1], None) |
Oper ("add ^d0, ^s0, 20", [t2], [t1], None) |
Oper ("b L123", [], [], Some [l]) |
Oper ("beq ^s0, ^s1 L123", [t1 ; t2], [], Some [l ; l']) |
Label ("L321:", l') |
:
» suffixant l'étiquette.Move ("move ^d0, ^s0", t2, t1) |
let arg_registers = [a0; a1; a2; a3] and res_registers = [v0] and caller_save_registers = [t0; t1; t2; t3; t4; t5; t6; t7; t8; t9] and callee_save_registers = [ra ; s0; s1; s2; s3; s4; s5; s6; s7] (* NB ra *) let special_registers = [fp; gp; sp; zero] let unused_registers = [at; v1; k0; k1;] |
type 'a t (* Créer une table *) val create : 'a -> 'a t (* Ajouter un element à la fin de la table *) val emit : 'a t -> 'a -> unit (* Vider la table dans une liste *) val trim_to_list : 'a t -> 'a list |
(* le typage de Caml exige cet argument *) let my_table = Table.create (Oper ("nop", [], [], None)) let emit ins = Table.emit my_table ins let emit_move d s = emit (Move ("move ^d0, ^s0", s, d)) let memo_of_op = function | Uplus -> "addu" (* addition non signée, pour les calculs d'adresse *) ... | Ne -> "sne " (* opérations booléennes *) let emit_op3 op d s0 s1 = emit (Oper (memo_of_op op^" ^d0, ^s0, ^s1"),[s0 ; s1], [d], None) |
let rec emit_exp e = match e with (* Temporaire *) | Temp t -> t (* Constantes *) | Const 0 -> zero (* c'est un registre *) | Const i -> let d = new_temp () in emit (Oper ("li ^d0, "^string_of_int i, [], [d], None) ; d |
() : unit
).(* Opérations *) | Bin ((Plus|Times|Uplus) as op, Const i, e2) -> emit_binop op e2 (Const i) | Bin (op, e1, e2) -> emit_binop op e1 e2 | ... and emit_binop op e1 e2 = match e2 with | Const i when seize_bits i -> let s = emit_exp e1 and d = new_temp () in emit_op2 op d s i ; d | _ -> let s0 = emit_exp e1 and s1 = emit_exp e2 and d = new_temp () in emit_op3 op d s0 s1 ; d |
let emit_jal lab sources dests = emit (Oper ("jal "^lab, sources, dest, None)) let emit_call2 f e1 e2 = emit_move a0 (emit_exp e1) ; emit_move a1 (emit_exp e2) ; let lab = Gen.label_string (Frame.frame_name f) in emit_jal lab [a0; a1] (ra::v0::args_registers@caller_save_registers) let is_fun = match Frame.frame_result f with Some _ -> true | None -> false in if is_fun then Some v0 else None |
emit_jal lab [a0; a1] (ra::v0::args_registers@caller_save_registers) |
jal
comme remplaçant toutes les
instructions de son corps (approximation des sources et des
destinations, selon les conventions d'appel).
let emit_fun f body = (* f est le frame *) let saved_callees = emit_prolog f in List.iter (fun i -> emit_stm f i) body ; emit_epilog f saved_callees ; Table.trim_to_list my_table |
f_size = 12 # mis là après l'allocation de registres # Code produit par le sélecteur f: # prologue de f subu $sp, $sp, f_size ... f_end: # épilogue de f ... addu $sp, $sp, f_fize j $ra |
f: # prologue de f move $ra, $111 move $s0, $112 ... f_end: # épilogue de f move $111, $ra move $112, $s0 |
emit (Oper "j $ra", v0::callee_save_registers, [], Some []) |
j
$ra
comme approximant toutes les instructions qui peuvent suivre.let emit_prolog_2 f = let f_size = Gen.label_string (Frame.frame_label f)^"_size" in (* point d'entrée et allocation du frame *) emit_label (Frame.frame_label f) ; emit (Oper ("subu $sp, $sp, "^f_size, [], [], None)) ; (* sauvegarde des callee-saves *) let saved_ra = new_temp () and saved_s0 = new_temp () ; emit_move saved_ra ra ; emit_move saved_s0 s0 ; (* récupérer les arguments *) let [t1 ; t2] = Frame.frame_args f in emit_move t1 a0 ; emit_move t2 a1 ; (* rendre les sauvegardes des callee-saves, pour l'épilogue *) [saved_ra ; saved_s0] |
program var x : integer ; function fact (n : integer) : integer; begin if n <= 1 then fact := 1 else fact := n * fact (n - 1); end ; begin read (x); writeln (fact (x)) end. |
function fact args = $t108, result = $t107 Cjump L12 L13 (<= $t108 1) L13: (set $t109 (call fact (- $t108 1))) (set $t107 (* $t108 $t109)) Jump fact_end L12: (set $t107 1) |
procedure main (set $t110 (call read_int)) (setmem $t28 $t110) (set $t111 (call fact (mem $t28))) Exp (call println_int $t111) |
|
|
|
|
Ce document a été traduit de LATEX par HEVEA