diff --git a/Sujet.pdf b/Sujet.pdf
index 353998034bf772d40308012fcade67ca4a22e1d3..fee3b5191a38a331944da73049353c94da487764 100644
Binary files a/Sujet.pdf and b/Sujet.pdf differ
diff --git a/alpaga/grammar_lexer.mll b/alpaga/grammar_lexer.mll
index 5716c08bf5e1d840a78e8f28313376110a2ae922..e2802373e089f6071d553ed23d371275404d9e67 100644
--- a/alpaga/grammar_lexer.mll
+++ b/alpaga/grammar_lexer.mll
@@ -1,5 +1,6 @@
 {
 open Grammar_parser_yacc
+open Lexing
 }
 
 let digit = ['0'-'9']
diff --git a/src/elang_gen.ml b/src/elang_gen.ml
index 8c08406e29016e99b565a08bc9153ab790446374..e8f9cd6922ac226fc7496be037d92ae7f351f476 100644
--- a/src/elang_gen.ml
+++ b/src/elang_gen.ml
@@ -81,9 +81,8 @@ let make_fundef_of_ast (a: tree) : (string * efun) res =
 
 let make_eprog_of_ast (a: tree) : eprog res =
   match a with
-  | Node (Tlistglobdef, [a]) ->
-    make_fundef_of_ast a >>= fun (fname, efun) ->
-    OK [(fname, Gfun efun)]
+  | Node (Tlistglobdef, l) ->
+    list_map_res (fun a -> make_fundef_of_ast a >>= fun (fname, efun) -> OK (fname, Gfun efun)) l
   | _ ->
     Error (Printf.sprintf "make_fundef_of_ast: Expected a Tlistglobdef, got %s."
              (string_of_ast a))
diff --git a/src/linear_liveness.ml b/src/linear_liveness.ml
index 5459485e17caf0b200c1ac25e50edf9701c3ba31..0a5891e75cfe8718612141f84e5e97e86f8b377c 100644
--- a/src/linear_liveness.ml
+++ b/src/linear_liveness.ml
@@ -5,11 +5,75 @@ open Utils
 open Linear
 open Rtl
 
+let gen_live (i: rtl_instr) =
+  match i with
+  | Rbinop (b, rd, rs1, rs2) -> Set.of_list [rs1; rs2]
+  | Rprint rs
+  | Runop (_, _, rs) -> Set.singleton rs
+  | Rconst (_, _) -> Set.empty
+  | Rbranch (_, rs1, rs2, _) -> Set.of_list [rs1; rs2]
+  | Rjmp _ -> Set.empty
+  | Rmov (_, rs) -> Set.singleton rs
+  | Rret r -> Set.singleton r
+  | Rlabel _ -> Set.empty
 
+let kill_live (i: rtl_instr) =
+  match i with
+  | Rbinop (_, rd, _, _)
+  | Runop (_, rd,_)
+  | Rconst (rd, _)
+  | Rmov (rd,_) -> Set.singleton rd
+  | Rbranch (_, _, _, _)
+  | Rprint _
+  | Rret _
+  | Rjmp _
+  | Rlabel _ -> Set.empty
 
-   let liveness_instrs linearfunbody =
-   (Hashtbl.create 0, Hashtbl.create 0)
+let linear_succs (ins: rtl_instr) i labels =
+  match ins with
+  | Rbranch(_, _, _, s1) -> [Hashtbl.find_default labels s1 0; i+1]
+  | Rjmp s -> [Hashtbl.find_default labels s 0]
+  | Rret r -> []
+  | _ -> [i+1]
 
+let setup_labels insl =
+  let labels = Hashtbl.create 17 in
+  List.iteri (fun i ins ->
+      match ins with
+      | Rlabel l -> Hashtbl.replace labels l i
+      | _ -> ()
+    ) insl;
+  labels
+
+let add_changes h k v =
+  let orig = Hashtbl.find_default h k Set.empty in
+  Hashtbl.replace h k v;
+  not (Set.equal v orig)
+
+let iter_liveness insl live_in live_out labels =
+  List.fold_lefti (fun changed i ins ->
+
+      let gl = gen_live ins in
+      let kl = kill_live ins in
+      let oi = Hashtbl.find_default live_out i Set.empty in
+      let newin = Set.union gl (Set.diff oi kl) in
+      let changed = add_changes live_in i newin || changed in
+      let succs = linear_succs ins i labels in
+      let j = List.fold_left (fun j succ ->
+          Set.union j (Hashtbl.find_default live_in succ Set.empty)
+        ) Set.empty succs in
+      add_changes live_out i j || changed
+    ) false insl
+
+let liveness_instrs insns =
+  let live_in = Hashtbl.create 17 in
+  let live_out = Hashtbl.create 17 in
+  let labels = setup_labels insns in
+  let rec aux () =
+    if iter_liveness insns live_in live_out labels
+    then aux ()
+    else (live_in, live_out) in
+  aux ()
 
 let liveness_linear_prog lp =
   let lives = Hashtbl.create 17 in
diff --git a/src/ltl_gen.ml b/src/ltl_gen.ml
index 5244b3eb35eb83919317b31aed97075efc3ab5c9..3a7b6172a3befdb7ea476ed2f500523afa671687 100644
--- a/src/ltl_gen.ml
+++ b/src/ltl_gen.ml
@@ -31,37 +31,412 @@ let make_sp_sub v =
 let make_sp_add v =
   [LAddi(reg_sp, reg_sp, v)]
 
+(* Moving between locations. [src] and [dst] are locations. [make_loc_mov src
+   dst] generates instructions so that the value in [src] ends up in [dst],
+   where [src] and [dst] can be registers [Reg r] or stack offsets [Stk o].
+*)
+let make_loc_mov src dst =
+  match src, dst with
+  | Stk osrc , Stk odst ->
+    let rtmp = reg_tmp1 in
+    [LLoad(rtmp, reg_fp, !Archi.wordsize * osrc, !Archi.wordsize);
+     LStore(reg_fp, !Archi.wordsize * odst, rtmp, !Archi.wordsize)]
+  | Stk osrc, Reg rdst ->
+    [LLoad(rdst, reg_fp, !Archi.wordsize * osrc, !Archi.wordsize)]
+  | Reg rsrc, Stk ofst ->
+    [LStore(reg_fp, !Archi.wordsize * ofst, rsrc, !Archi.wordsize)]
+  | Reg rsrc, Reg rdst ->
+    [LMov(rdst,rsrc)]
 
+(* load_loc tmp allocation r = (l, r'). Loads the equivalent of RTL register r
+   in a LTL register r'. tmpis used if necessary. *)
+let load_loc tmp allocation r =
+  match Hashtbl.find_option allocation r with
+  | None ->
+    Error (Format.sprintf "Unable to allocate RTL register r%d." r)
+  | Some (Stk o) -> OK ([LLoad(tmp, reg_fp, !Archi.wordsize * o, !Archi.wordsize)], tmp)
+  | Some (Reg r) -> OK ([], r)
 
+(* store_loc tmp allocation r = (l, r'). I want to write in RTL register r.
+   Tells me that I just have to write to LTL register r' and execute l. *)
+let store_loc tmp allocation r =
+  match Hashtbl.find_option allocation r with
+  | None ->
+    Error (Format.sprintf "Unable to allocate RTL register r%d." r)
+  | Some (Stk o) -> OK ([LStore(reg_fp, !Archi.wordsize * o, tmp, !Archi.wordsize)], tmp)
+  | Some (Reg r) -> OK ([], r)
 
-   let ltl_prog_of_linear_with_alloc_order alloc_order  lp =
-   let prog = List.map (function
-        (fname, Gfun f) ->
-        (fname, Gfun {
-   ltlfunargs = 0;
-   ltlfunbody = [];
-   ltlfuninfo = [];
-   ltlregalloc = [];
-   }
-    )) lp in
-   prog
+(* saves registers in [to_save] on the stack at offsets [fp + o, fp + o - 8, fp
+   + o - 16...]. Returns:
 
+   - an association list [(reg,ofs)] (meaning register reg is saved at [fp+ofs])
+   - the list of store instructions
+   - the next offset to be written.
+*)
+let save_caller_save to_save ofs =
+  List.fold_left (fun (instrs, arg_saved, ofs) reg ->
+      (instrs @ [LStore(reg_fp, ofs, reg, !Archi.wordsize)],
+       (reg,ofs)::arg_saved, ofs - !Archi.wordsize)
+    ) ([], [], ofs) to_save
 
+(* Given a list [(reg,ofs)], loads [fp+ofs] into [reg]. *)
+let restore_caller_save =
+  List.map (fun (reg, ofs) -> LLoad(reg, reg_fp, ofs, !Archi.wordsize))
 
-let alloc_order_st = [
-  reg_s1; reg_s2; reg_s3; reg_s4; reg_s5;
-  reg_s6; reg_s7; reg_s8; reg_s9; reg_s10; reg_s11;
-  reg_t2; reg_t3; reg_t4; reg_t5; reg_t6;
-]
+let num_parameters_passed_on_stack regs =
+  let r = List.length regs - number_of_arguments_passed_in_registers in
+  Stdlib.max 0 r
 
-let alloc_order_ts = [
-  reg_t2; reg_t3; reg_t4; reg_t5; reg_t6;
+
+(* Given a list or RTL registers [rargs], we want to load their values in LTL
+   argument registers a0-7. But while writing these registers, we may overwrite
+   the value of some registers before we actually read them.
+
+   For example if [r1 -> a1] and [r2 -> a0], and we want to load [r1] in [a0]
+   and [r2] in [a1] (because a function call f(r1,r2) occurs), the following
+   would happen :
+
+   mv a0, a1
+   mv a1, a0
+
+   But the value in [a1] will not be the value that was originally in RTL reg
+   [r2].
+
+   Hence, we keep track of the registers like [a1] that are going to be written
+   before being read, and those will be saved on the stack.
+*)
+let overwritten_args rargs allocation =
+
+  (* [ltl_args] contains the locations of RTL args after allocation. *)
+    list_map_res (fun r -> match Hashtbl.find_option allocation r with
+        | None -> Error (Format.sprintf
+                              "pass_parameters: Couldn't allocate register r%d."
+                              r)
+        | Some loc -> OK loc
+      ) rargs >>= fun ltl_args ->
+
+  let (overwritten, read_overwritten) =
+    List.fold_lefti (fun (overwritten, read_overwritten) i (src: loc) ->
+        (* [overwritten] contains the list of registers that have been written
+           to.
+
+           [read_overwritten] contains the list of registers that have been read
+           after being written to. *)
+        let read_overwritten =
+          match src with
+          | Reg rs -> if Set.mem rs overwritten
+            then Set.add rs read_overwritten
+            else read_overwritten
+          | Stk _ -> read_overwritten
+        in
+        let overwritten =
+          if i < number_of_arguments_passed_in_registers
+          then Set.add (starting_arg_register + i) overwritten
+          else overwritten
+        in (overwritten, read_overwritten)
+      ) (Set.empty,Set.empty) ltl_args in
+  OK read_overwritten
+
+
+
+(* [pass_parameters rargs allocation arg_saved ofs] generates code to pass
+   parameters in RTL registers rargs. [allocation] maps RTL registers to LTL
+   locations, [arg_saved] contains saved registers, and [ofs] says where,
+   relative to reg_fp we may save more registers if needed. *)
+let pass_parameters rargs allocation arg_saved =
+  (* LTL locations corresponding to RTL arguments.  *)
+  list_map_res (fun r -> match Hashtbl.find_option allocation r with
+      | None ->
+        Error (Format.sprintf
+                 "pass_parameters: Couldn't allocate register r%d." r)
+      | Some loc -> OK loc
+    ) rargs >>= fun ltl_args ->
+
+  (* Relocation of arguments may be necessary if, e.g. a1 must be passed as
+     first argument (in a0) and a0 must be passed as second argument (in a1). In
+     that situation, a temporary must be used. These registers (a0 and a1) would
+     have been saved before on the stack and the relocation information is
+     available in arg_saved. *)
+  let reloc_loc overwritten loc =
+    match loc with
+    | Stk o -> OK loc
+    | Reg r -> if List.mem r overwritten
+      then match List.assoc_opt r arg_saved with
+        | None -> Error (Format.sprintf "Register %s has been overwritten, \
+                                         yet it has not been saved."
+                           (print_reg r))
+        | Some newloc -> OK (Stk newloc)
+      else OK loc
+  in
+  (* Iterates over the list of LTL arguments. Generates 4 things:
+
+     - [overwritten] is the set of registers that are overwritten during
+       parameter passing. If a register has been overwritten, then we use its copy
+       on the stack; otherwise we can use it directly.
+
+     - [instrs] is a list of instructions for the arguments passed in registers.
+
+     - [pushes] is a list of push pseudo-instructions for every additional
+       argument. The two lists are built separately so that we can build [pushes]
+       backwards so that e.g. the 9th argument is at the top of the stack at the
+       end, and e.g. the 15th at higher addresses.
+
+     - [npush] is the number of arguments that were pushed to the stack. *)
+
+  List.fold_lefti (fun acc i (src: loc) ->
+      acc >>= fun (overwritten, instrs, pushes, npush) ->
+      reloc_loc overwritten src >>= fun src ->
+      let (overwritten, l,pushes, npush) =
+        if i < number_of_arguments_passed_in_registers
+        then let rd = starting_arg_register + i in
+          begin match src with
+            | Reg rs ->  (rd::overwritten, [LMov(rd, rs)],[], npush)
+            | Stk o -> (rd::overwritten,
+                        [LLoad(rd, reg_fp, !Archi.wordsize * o, !Archi.wordsize)],
+                        [], npush)
+          end else
+          begin match src with
+            | Reg rs -> (overwritten, [], make_push rs@pushes, npush+1)
+            | Stk o ->  (overwritten, [],
+                         LLoad(reg_tmp1, reg_fp, !Archi.wordsize * o, !Archi.wordsize)
+                         ::make_push reg_tmp1 @ pushes,
+                         npush+1)
+          end
+      in
+      OK (overwritten, instrs@l, pushes, npush)
+    ) (OK ([], [], [], 0)) ltl_args >>=
+  fun (overwritten, instrs, pushes, npush) ->
+  OK (instrs@pushes, npush)
+
+let written_rtl_regs_instr (i: rtl_instr) =
+  match i with
+  | Rbinop (_, rd, _, _)
+  | Runop (_, rd, _)
+  | Rconst (rd, _)
+  | Rmov (rd, _) -> Set.singleton rd
+  | Rprint _
+  | Rret _
+  | Rlabel _
+  | Rbranch (_, _, _, _)
+  | Rjmp _ -> Set.empty
+
+let read_rtl_regs_instr (i: rtl_instr) =
+  match i with
+  | Rbinop (_, _, rs1, rs2)
+  | Rbranch (_, rs1, rs2, _) -> Set.of_list [rs1; rs2]
+
+  | Rprint rs
+  | Runop (_, _, rs)
+  | Rmov (_, rs)
+  | Rret rs -> Set.singleton rs
+
+  | Rlabel _
+  | Rconst (_, _)
+  | Rjmp _ -> Set.empty
+
+let read_rtl_regs (l: rtl_instr list) =
+  List.fold_left (fun acc i -> Set.union acc (read_rtl_regs_instr i))
+    Set.empty l
+
+let written_rtl_regs (l: rtl_instr list) =
+  List.fold_left (fun acc i -> Set.union acc (written_rtl_regs_instr i))
+    Set.empty l
+
+let rtl_to_ltl_registers allocation l =
+  Set.filter_map (fun rtlreg ->
+      match Hashtbl.find_option allocation rtlreg with
+      | Some (Stk ofs) -> None
+      | None -> None
+      | Some (Reg r) -> Some r) l
+
+(* Take the RTL registers used by RTL instructions in [l], apply allocation to
+   them. This gives a list of machine registers used by the LTL function. We
+   need to add also the registers that will be used for argument passing. *)
+
+let read_ltl_regs_clever fname l allocation =
+  read_rtl_regs l |> rtl_to_ltl_registers allocation
+let written_ltl_regs_clever fname l allocation =
+  written_rtl_regs l |> rtl_to_ltl_registers allocation
+
+let read_ltl_regs fname l allocation =
+  read_ltl_regs_clever fname l allocation
+
+let written_ltl_regs fname l allocation =
+  written_ltl_regs_clever fname l allocation
+
+(* We propose three different strategies for caller-save registers:
+   - [CSS_all] : save all registers before calling a function
+   - [CSS_read] : save all registers that are read in the calling function,
+     we might need them later in the function
+   - [CSS_live] : save all registers that are live after the call to the
+     function, this is more precise than [CSS_read].
+*)
+type caller_save_strategy =
+  | CSS_all
+  | CSS_read
+  | CSS_live
+
+let caller_save live_out allocation read_regs rargs
+    (strategy: caller_save_strategy) =
+  let l =
+    match strategy with
+    | CSS_all -> OK (range 32 |> Set.of_list)
+    | CSS_read -> OK read_regs
+    | CSS_live ->
+      let live_after = live_out in
+      let live_after_ltl = live_after |> rtl_to_ltl_registers allocation in
+      overwritten_args rargs allocation >>= fun overwritten_args_tosave ->
+      OK (Set.union live_after_ltl overwritten_args_tosave)
+  in
+  l >>= fun l -> OK (Set.intersect l (Set.of_list (arg_registers @ reg_tmp)))
+
+(* This generates LTL instructions for a given Linear/RTL instruction. In most
+   cases, the transformation amounts to 'loading' RTL registers in LTL locations
+   and emitting the straightforward corresponding LTL instructions. This uses
+   load_loc and store_loc, described above, a lot. The most interesting case is
+   call instructions. Indeed, in that case, we emit code for saving and
+   restoring caller-save registers before and after the call, respectively. The
+   registers to be saved are computed as the set of Risc-V registers marked as
+   caller-save (a0-a7,t0-t6) intersected with the registers that are read in the
+   code of the caller. (The rationale being, if we don't read this variable,
+   then we don't need its value to be preserved across function calls.) These
+   registers are saved at [fp - 8 * (curstackslot + 1)] *)
+let ltl_instrs_of_linear_instr fname live_out allocation read_regs
+    numspilled epilogue_label ins =
+  match ins with
+  | Rbinop (b, rd, rs1, rs2) ->
+    load_loc reg_tmp1 allocation rs1 >>= fun (l1, r1) ->
+    load_loc reg_tmp2 allocation rs2 >>= fun (l2, r2) ->
+    store_loc reg_tmp1 allocation rd >>= fun (ld, rd) ->
+    OK (l1 @ l2 @ LBinop(b, rd, r1, r2) :: ld)
+  | Runop (u, rd, rs) ->
+    load_loc reg_tmp1 allocation rs >>= fun (l1,r1) ->
+    store_loc reg_tmp1 allocation rd >>= fun (ld, rd) ->
+    OK (l1 @ LUnop(u, rd, r1) :: ld)
+  | Rconst (rd, i) ->
+    store_loc reg_tmp1 allocation rd >>= fun (ld, rd) ->
+    OK (LConst(rd, i)::ld)
+  | Rbranch (cmp, rs1, rs2, s1) ->
+    load_loc reg_tmp1 allocation rs1 >>= fun (l1, r1) ->
+    load_loc reg_tmp2 allocation rs2 >>= fun (l2, r2) ->
+    OK (l1 @ l2 @ [LBranch(cmp, r1, r2, Format.sprintf "%s_%d" fname s1)])
+  | Rjmp s -> OK [LJmp (Format.sprintf "%s_%d" fname s)]
+  | Rmov (rd, rs) ->
+    load_loc reg_tmp1 allocation rs >>= fun (ls, rs) ->
+    store_loc reg_tmp1 allocation rd >>= fun (ld, rd) ->
+    OK (ls @ LMov(rd, rs) :: ld)
+  | Rprint r ->
+
+    let (save_a_regs, arg_saved, ofs) =
+      save_caller_save
+        (range 32)
+        (- !Archi.wordsize * (numspilled+1)) in
+    let parameter_passing =
+      match Hashtbl.find_option allocation r with
+      | None -> Error (Format.sprintf "Could not find allocation for register %d\n" r)
+      | Some (Reg rs) -> OK [LMov(reg_a0, rs)]
+      | Some (Stk o) -> OK [LLoad(reg_a0, reg_fp, !Archi.wordsize * o, !Archi.wordsize)]
+    in
+    parameter_passing >>= fun parameter_passing ->
+    OK (LComment "Saving a0-a7,t0-t6" :: save_a_regs @
+        LAddi(reg_sp, reg_s0, ofs) ::
+        parameter_passing @
+        LCall "print" ::
+        LComment "Restoring a0-a7,t0-t6" :: restore_caller_save arg_saved)
+
+  | Rret r ->
+    load_loc reg_tmp1 allocation r >>= fun (l,r) ->
+    OK (l @ [LMov (reg_ret, r) ; LJmp epilogue_label])
+  | Rlabel l -> OK [LLabel (Format.sprintf "%s_%d" fname l)]
+
+(** Retrieves the location of the n-th argument (in the callee). The first 8 are
+   passed in a0-a7, the next are passed on the stack. *)
+let retrieve_nth_arg n numcalleesave =
+  let thr = number_of_arguments_passed_in_registers in
+  if n < thr
+  then Reg (n + starting_arg_register)
+  else Stk ((numcalleesave + n-thr))
+
+(* This function creates a LTL function out of a Linear function. In addition to
+   using machine registers instead of ideal registers, it deals with saving and
+   restoring callee-save registers. The function prologue consists of saving
+   these callee-save registers, making the frame pointer to sp, and saving space
+   on the stack for the variables that would reside on the stack (i.e. spilled -
+   they go from [s0] to [s0+curstackslot] (curstackslot is negative, and
+   returned by the register allocation)). The function epilogue restores sp to
+   the value stored in s0 (fp), restore all the callee-save registers and jumps
+   back to [ra]. *)
+let ltl_fun_of_linear_fun linprog
+    (({ linearfunargs; linearfunbody; linearfuninfo }): linear_fun) fname
+    (live_in,live_out) (allocation, numspilled) =
+  List.iteri (fun i pr ->
+      Hashtbl.replace allocation pr (retrieve_nth_arg i 0)
+    ) linearfunargs;
+  let written_regs = Set.add reg_ra
+      (Set.add reg_fp
+         (written_ltl_regs fname linearfunbody allocation)) in
+  let callee_saved_regs =
+    Set.intersect (Set.of_list callee_saved) written_regs in
+  List.iteri (fun i pr ->
+      Hashtbl.replace allocation pr
+        (retrieve_nth_arg i (Set.cardinal callee_saved_regs))
+    ) linearfunargs;
+
+  let max_label =
+    List.fold_left (fun acc i ->
+        match i with
+          Rlabel l -> Stdlib.max l acc
+        | _ -> acc)
+      0 linearfunbody in
+  let epilogue_label = Format.sprintf "%s_%d" fname (max_label + 1) in
+  let prologue =
+    List.concat (List.map make_push (Set.to_list callee_saved_regs)) @
+    LMov (reg_fp, reg_sp) ::
+    make_sp_sub (numspilled * !Archi.wordsize) @
+    [LComment "end prologue"] in
+  let epilogue = LLabel epilogue_label ::
+                 LMov(reg_sp, reg_fp) ::
+                 List.concat (List.map make_pop
+                                (List.rev (Set.to_list callee_saved_regs))) @
+                 [LJmpr reg_ra] in
+  let read_regs_f = read_ltl_regs fname linearfunbody allocation in
+  list_map_resi (fun i ->
+      ltl_instrs_of_linear_instr fname (Hashtbl.find_default live_out i Set.empty)
+        allocation read_regs_f numspilled epilogue_label) linearfunbody
+  >>= fun l ->
+  let instrs = List.concat l 
+  in
+  OK {
+    ltlfunargs = List.length linearfunargs;
+    ltlfunbody = prologue @ instrs @ epilogue;
+    ltlfuninfo = linearfuninfo;
+    ltlregalloc = Hashtbl.bindings allocation;
+  }
+
+
+let allocable_registers = Set.of_list [
   reg_s1; reg_s2; reg_s3; reg_s4; reg_s5;
   reg_s6; reg_s7; reg_s8; reg_s9; reg_s10; reg_s11;
+  reg_t2; reg_t3; reg_t4; reg_t5; reg_t6;
 ]
 
-let ltl_prog_of_linear lp () =
-  let alloc_order =
-    if !Options.alloc_order_st then alloc_order_st else alloc_order_ts in
-  ltl_prog_of_linear_with_alloc_order alloc_order lp
+let ltl_prog_of_linear lp =
+  let lives = liveness_linear_prog lp in
+  let allocations = regalloc lp lives allocable_registers in
+  let prog = list_map_res (function
+        (fname, Gfun f) ->
+        let f_alloc =
+          match Hashtbl.find_option allocations fname with
+          | None -> (Hashtbl.create 0, 0)
+          | Some (rig, allocation, next_stack_slot) -> (allocation, - next_stack_slot)
+        in
+        let f_lives =
+          match Hashtbl.find_option lives fname with
+          | None -> (Hashtbl.create 0, Hashtbl.create 0)
+          | Some x -> x
+        in
+        ltl_fun_of_linear_fun lp f fname f_lives f_alloc >>= fun f ->
+        OK (fname, Gfun f)
+    ) lp in
+  prog
 
diff --git a/src/ltl_print.ml b/src/ltl_print.ml
index b4421cfbedfab7b81d908c1df22bdd4c0f9e018f..bdabe2569a3d8f27638ba06ee2f40cf0380c7a14 100644
--- a/src/ltl_print.ml
+++ b/src/ltl_print.ml
@@ -107,15 +107,16 @@ let dump_ltl_instr_list fname oc l =
       dump_ltl_instr oc ins;
       Format.fprintf oc "\n") l
 
+let dump_allocation oc fname alloc =
+  Format.fprintf oc "// In function %s\n" fname;
+  List.iter (fun (linr,ltlloc) ->
+      Format.fprintf oc "// LinReg %d allocated to %s\n" linr (print_loc ltlloc)
+    ) alloc
+
 let dump_ltl_fun oc fname lf =
+  dump_allocation oc fname lf.ltlregalloc;
   Format.fprintf oc "%s:\n" fname;
   dump_ltl_instr_list fname oc lf.ltlfunbody
 
 let dump_ltl_prog oc lp =
   dump_prog dump_ltl_fun oc lp
-
-let dump_allocation fname alloc =
-  Format.printf "In function %s\n" fname;
-  Hashtbl.iter (fun linr ltlloc ->
-      Format.printf "LinReg %d allocated to %s\n" linr (print_loc ltlloc)
-    ) alloc
diff --git a/src/main.ml b/src/main.ml
index f53ff78eda9922bf30423bbcb81deffeca546a54..f9a4a22e5e43e17f9ba1b79dceda4397e11b4f6a 100644
--- a/src/main.ml
+++ b/src/main.ml
@@ -67,6 +67,11 @@ let speclist =
     ("-riscv-run", Arg.Set riscv_run, "Run RISC-V program.");
     ("-no-dump", Arg.Set no_dump, "Do not dump anything but the .s file");
     ("-no-dot", Arg.Set no_dot, "Do not call dot on CFG dumps (default false)");
+    ("-clever-regalloc", Arg.Unit (fun () -> naive_regalloc := false), "Use the graph coloring algorithm for register allocation.");
+    ("-naive-regalloc", Arg.Unit (fun () -> naive_regalloc := true),
+     "Use the naive algorithm for register allocation (all pseudo-registers go on the stack).");
+    ("-rig-dump", Arg.String (fun s -> rig_dump := Some s),
+    "Path to output the register interference graph");
     ("-all-run", Arg.Unit (fun () ->
          e_run := true;
          cfg_run := true;
@@ -115,7 +120,11 @@ let results = ref []
 
 let run step flag eval p =
   if flag then begin
-    begin match eval Format.str_formatter p !heapsize !params with
+    let res = match eval Format.str_formatter p !heapsize !params with
+      | exception e ->
+        Error (Printexc.to_string e)
+      | e -> e in
+    begin match res with
       | OK v ->
         let output = Format.flush_str_formatter () in
         results := !results @ [RunRes { step ; retval = v; output; error = None}];
@@ -149,21 +158,6 @@ let record_compile_result ?error:(error=None) ?data:(data=[]) step =
   let data = if not !Options.nostats then `List data else `Null in
   results := !results @ [CompRes { step; error; data}]
 
-let dump file dumpf p additional_command =
-  begin match file with
-    | None -> ()
-    | Some file ->
-      let oc, close = 
-        if file = "-"
-        then (Format.std_formatter, fun _ -> ())
-        else
-          let oc = open_out file in
-          (Format.formatter_of_out_channel oc, fun () -> close_out oc)
-      in
-      dumpf oc p; close ();
-      if file <> "-" then additional_command file ()
-  end
-
 
 
 let process_output_to_list2 = fun command ->
@@ -224,7 +218,13 @@ let exec_rv_prog ltl basename oc rvp heapsize params =
       f
   in
   let error = ref None in
-  dump (Some rvp) dump_riscv_prog ltl (fun file () -> error := compile_rv basename file ());
+  dump (Some rvp) (fun oc p ->
+      match dump_riscv_prog oc p with
+      | OK _ -> ()
+      | Error msg -> error := Some msg
+    ) ltl (fun file () ->
+      if !error = None
+      then error := compile_rv basename file ());
   match !error with
   | Some e -> Error ("RiscV generation error:\n" ^e)
   | None ->
@@ -237,13 +237,6 @@ let exec_rv_prog ltl basename oc rvp heapsize params =
       OK (Some ret)
     with _ -> OK None
 
-let call_dot report_sectid report_secttitle file () : unit =
-  if not !Options.no_dot
-  then begin
-    let r = Sys.command (Format.sprintf "dot -Tsvg %s -o %s.svg" file file) in
-    add_to_report report_sectid report_secttitle (Img (Filename.basename file^".svg"));
-    ignore r
-  end
 
 let _ =
   Arg.parse speclist (fun s -> ()) "Usage";
@@ -267,6 +260,7 @@ let _ =
           set_default cfg_dump basename ".cfg";
           set_default rtl_dump basename ".rtl";
           set_default linear_dump basename ".linear";
+          set_default rig_dump basename ".rig";
           set_default ltl_dump basename ".ltl";
         end;
 
@@ -275,89 +269,95 @@ let _ =
           ) $ fun tokens ->
             record_compile_result "Lexing";
             dump !show_tokens (fun oc tokens ->
-            List.iter (fun (tok,_) ->
-                Format.fprintf oc "%s\n" (string_of_symbol tok)
+                List.iter (fun (tok,_) ->
+                    Format.fprintf oc "%s\n" (string_of_symbol tok)
                   ) tokens) tokens (fun f () -> add_to_report "lexer" "Lexer" (Code (file_contents f)));
-        parse tokens () >>* (fun msg ->
-            record_compile_result ~error:(Some msg) "Parsing";
-          ) $ fun (ast, tokens) ->
-            record_compile_result "Parsing";
-            dump !ast_tree draw_ast_tree ast (call_dot "ast" "AST");
-            if !ast_dump then Format.printf "%s\n" (string_of_ast ast) else ();
-
-            match make_eprog_of_ast ast with
-            | Error msg -> record_compile_result ~error:(Some msg) "Elang"
-            | OK  ep ->
-            dump !e_dump dump_e ep (fun file () ->
-                add_to_report "e" "E" (Code (file_contents file)));
-            run "Elang" !e_run eval_eprog ep;
-
-            match cfg_prog_of_eprog ep with
-            | Error msg ->
-              record_compile_result ~error:(Some msg) "CFG";
-            | OK cfg ->
-            record_compile_result ~data:([(`Assoc (List.map (fun (fname,Prog.Gfun cfgfun) -> (fname, `Int (Cfg.size_fun cfgfun.cfgfunbody))) cfg))]) "CFG";
-
-            dump !cfg_dump dump_cfg_prog cfg (call_dot "cfg" "CFG");
-            run "CFG" !cfg_run eval_cfgprog cfg;
-
-            let cfg = optimize_loop_cfg cfg in
-            record_compile_result ~data:([(`Assoc (List.map (fun (fname,Prog.Gfun cfgfun) -> (fname, `Int (Cfg.size_fun cfgfun.cfgfunbody))) cfg))]) "CFG loops";
-            dump (!cfg_dump >*> fun s -> s ^ "0") dump_cfg_prog cfg
-              (call_dot "cfg-after-loop" "CFG after loop optim");
-            run "CFG after loop optim" !cfg_run_after_loop eval_cfgprog cfg;
-
-
-            let cfg = constant_propagation cfg in
-            record_compile_result ~data:([(`Assoc (List.map (fun (fname,Prog.Gfun cfgfun) -> (fname, `Int (Cfg.size_fun cfgfun.cfgfunbody))) cfg))]) "Constprop";
-            dump (!cfg_dump >*> fun s -> s ^ "1") dump_cfg_prog cfg
-              (call_dot "cfg-after-cstprop" "CFG after Constant Propagation");
-            run "CFG after constant_propagation" !cfg_run_after_cp eval_cfgprog cfg;
-
-            let cfg = dead_assign_elimination cfg in
-            record_compile_result ~data:([(`Assoc (List.map (fun (fname,Prog.Gfun cfgfun) -> (fname, `Int (Cfg.size_fun cfgfun.cfgfunbody))) cfg))]) "DeadAssign";
-            dump (!cfg_dump >*> fun s -> s ^ "2") dump_cfg_prog cfg
-              (call_dot "cfg-after-dae" "CFG after DAE");
-            run "CFG after dead_assign_elimination" !cfg_run_after_dae eval_cfgprog cfg;
-
-            let cfg = nop_elimination cfg in
-            record_compile_result ~data:([(`Assoc (List.map (fun (fname,Prog.Gfun cfgfun) -> (fname, `Int (Cfg.size_fun cfgfun.cfgfunbody))) cfg))]) "NopElim";
-            dump (!cfg_dump >*> fun s -> s ^ "3") dump_cfg_prog cfg
-              (call_dot "cfg-after-nop" "CFG after NOP elim");
-            run "CFG after nop_elimination" !cfg_run_after_ne eval_cfgprog cfg;
-
-
-            let rtl = rtl_of_cfg cfg in
-            dump !rtl_dump dump_rtl_prog rtl
-              (fun file () -> add_to_report "rtl" "RTL" (Code (file_contents file)));
-            run "RTL" !rtl_run exec_rtl_prog rtl;
-
-            let linear = linear_of_rtl rtl in
-            let lives = liveness_linear_prog linear in
-            dump !linear_dump (fun oc -> dump_linear_prog oc (Some lives)) linear
-              (fun file () -> add_to_report "linear" "Linear" (Code (file_contents file)));
-            run "Linear" !linear_run exec_linear_prog linear;
-
-            let linear = dse_prog linear lives in
-            record_compile_result "DSE";
-            dump (!linear_dump >*> fun s -> s ^ "1")
-              (fun oc -> dump_linear_prog oc (Some lives)) linear
-              (fun file () -> add_to_report "linear-after-dse" "Linear after DSE"
-                  (Code (file_contents file)));
-            run "Linear after DSE" !linear_run_after_dse exec_linear_prog linear;
-
-            let ltl = ltl_prog_of_linear linear () in
-            dump !ltl_dump dump_ltl_prog ltl
-              (fun file () -> add_to_report "ltl" "LTL" (Code (file_contents file)));
-            run "LTL" !ltl_run (exec_ltl_prog) ltl;
-            (if !ltl_debug then debug_ltl_prog input ltl !heapsize !params);
-
-            dump !riscv_dump dump_riscv_prog ltl (fun file () ->
-                add_to_report "riscv" "RISC-V" (Code (file_contents file));
-                ignore (compile_rv basename file ()));
-            if not !Options.nostart then begin
-              run "Risc-V" !riscv_run (exec_rv_prog ltl basename) !riscv_dump
-            end;
+            parse tokens () >>* (fun msg ->
+                record_compile_result ~error:(Some msg) "Parsing";
+              ) $ fun (ast, tokens) ->
+                record_compile_result "Parsing";
+                dump !ast_tree draw_ast_tree ast (call_dot "ast" "AST");
+                if !ast_dump then Format.printf "%s\n" (string_of_ast ast) else ();
+
+                match make_eprog_of_ast ast with
+                | Error msg -> record_compile_result ~error:(Some msg) "Elang"
+                | OK  ep ->
+                  dump !e_dump dump_e ep (fun file () ->
+                      add_to_report "e" "E" (Code (file_contents file)));
+                  run "Elang" !e_run eval_eprog ep;
+
+                  match cfg_prog_of_eprog ep with
+                  | Error msg ->
+                    record_compile_result ~error:(Some msg) "CFG";
+                  | OK cfg ->
+                    record_compile_result ~data:([(`Assoc (List.map (fun (fname,Prog.Gfun cfgfun) -> (fname, `Int (Cfg.size_fun cfgfun.cfgfunbody))) cfg))]) "CFG";
+
+                    dump !cfg_dump dump_cfg_prog cfg (call_dot "cfg" "CFG");
+                    run "CFG" !cfg_run eval_cfgprog cfg;
+
+                    let cfg = optimize_loop_cfg cfg in
+                    record_compile_result ~data:([(`Assoc (List.map (fun (fname,Prog.Gfun cfgfun) -> (fname, `Int (Cfg.size_fun cfgfun.cfgfunbody))) cfg))]) "CFG loops";
+                    dump (!cfg_dump >*> fun s -> s ^ "0") dump_cfg_prog cfg
+                      (call_dot "cfg-after-loop" "CFG after loop optim");
+                    run "CFG after loop optim" !cfg_run_after_loop eval_cfgprog cfg;
+
+
+                    let cfg = constant_propagation cfg in
+                    record_compile_result ~data:([(`Assoc (List.map (fun (fname,Prog.Gfun cfgfun) -> (fname, `Int (Cfg.size_fun cfgfun.cfgfunbody))) cfg))]) "Constprop";
+                    dump (!cfg_dump >*> fun s -> s ^ "1") dump_cfg_prog cfg
+                      (call_dot "cfg-after-cstprop" "CFG after Constant Propagation");
+                    run "CFG after constant_propagation" !cfg_run_after_cp eval_cfgprog cfg;
+
+                    let cfg = dead_assign_elimination cfg in
+                    record_compile_result ~data:([(`Assoc (List.map (fun (fname,Prog.Gfun cfgfun) -> (fname, `Int (Cfg.size_fun cfgfun.cfgfunbody))) cfg))]) "DeadAssign";
+                    dump (!cfg_dump >*> fun s -> s ^ "2") dump_cfg_prog cfg
+                      (call_dot "cfg-after-dae" "CFG after DAE");
+                    run "CFG after dead_assign_elimination" !cfg_run_after_dae eval_cfgprog cfg;
+
+                    let cfg = nop_elimination cfg in
+                    record_compile_result ~data:([(`Assoc (List.map (fun (fname,Prog.Gfun cfgfun) -> (fname, `Int (Cfg.size_fun cfgfun.cfgfunbody))) cfg))]) "NopElim";
+                    dump (!cfg_dump >*> fun s -> s ^ "3") dump_cfg_prog cfg
+                      (call_dot "cfg-after-nop" "CFG after NOP elim");
+                    run "CFG after nop_elimination" !cfg_run_after_ne eval_cfgprog cfg;
+
+
+                    let rtl = rtl_of_cfg cfg in
+                    dump !rtl_dump dump_rtl_prog rtl
+                      (fun file () -> add_to_report "rtl" "RTL" (Code (file_contents file)));
+                    run "RTL" !rtl_run exec_rtl_prog rtl;
+
+                    let linear = linear_of_rtl rtl in
+                    let lives = liveness_linear_prog linear in
+                    dump !linear_dump (fun oc -> dump_linear_prog oc (Some lives)) linear
+                      (fun file () -> add_to_report "linear" "Linear" (Code (file_contents file)));
+                    run "Linear" !linear_run exec_linear_prog linear;
+
+                    let linear = dse_prog linear lives in
+                    record_compile_result "DSE";
+                    dump (!linear_dump >*> fun s -> s ^ "1")
+                      (fun oc -> dump_linear_prog oc (Some lives)) linear
+                      (fun file () -> add_to_report "linear-after-dse" "Linear after DSE"
+                          (Code (file_contents file)));
+                    run "Linear after DSE" !linear_run_after_dse exec_linear_prog linear;
+
+                    match ltl_prog_of_linear linear with
+                    | Error msg -> record_compile_result ~error:(Some msg) "LTL"
+                    | OK ltl ->
+                      dump !ltl_dump dump_ltl_prog ltl
+                        (fun file () -> add_to_report "ltl" "LTL" (Code (file_contents file)));
+                      run "LTL" !ltl_run (exec_ltl_prog) ltl;
+                      (if !ltl_debug then debug_ltl_prog input ltl !heapsize !params);
+
+                      dump !riscv_dump (fun oc p ->
+                          match dump_riscv_prog oc p with
+                          | OK _ -> ()
+                          | Error msg -> record_compile_result ~error:(Some msg) "RISCV"
+                        ) ltl (fun file () ->
+                          add_to_report "riscv" "RISC-V" (Code (file_contents file));
+                          ignore (compile_rv basename file ()));
+                      if not !Options.nostart then begin
+                        run "Risc-V" !riscv_run (exec_rv_prog ltl basename) !riscv_dump
+                      end;
 
       end;
 
diff --git a/src/options.ml b/src/options.ml
index 53c33dfcf99529e7d6ff99ae59174f270a3d2208..b6bdd51360827630c4e5ca2f18a02186ac4bef2f 100644
--- a/src/options.ml
+++ b/src/options.ml
@@ -32,3 +32,5 @@ let no_dump = ref false
 let no_dot = ref false
 
 let alloc_order_st = ref true
+let naive_regalloc = ref true
+let rig_dump : string option ref = ref None
diff --git a/src/regalloc.ml b/src/regalloc.ml
index c0b28144a4752c2753e53e2127e5da0c88252105..f625cce21ab616f7cf2652daaa4481d0e036d6f1 100644
--- a/src/regalloc.ml
+++ b/src/regalloc.ml
@@ -5,27 +5,306 @@ open Prog
 open Linear
 open Rtl
 open Linear_liveness
+open Utils
+open Report
+open Options
+
+
+
+(* Allocation de registres *)
+
+(* Nous allons procéder à l'allocation de registres, par coloration de graphe
+   d'interférences.
+
+   Le but de l'allocateur est d'associer à chaque pseudo-registre utilisé dans
+   une fonction Linear, un emplacement (type [loc]). *)
 
-type regalloc_decision = Spill of int | NoSpill of int
 type loc = Reg of int | Stk of int
 
+(* Un emplacement (location en anglais) est soit un registre machine (identifié
+   par son numéro [r] entre 0 et 31 inclus) : [Reg r], soit un emplacement sur
+   la pile [Stk o] signifiant un décalage de [o] octets par rapport au pointeur
+   de trame présent dans le registre [s0] (aussi appelé [fp] pour frame
+   pointer). *)
 
+(* Nous vous fournissons, ci-dessous, une implémentation naïve qui évince tous
+   les pseudo-registres sur la pile. *)
 
+let regs_in_instr i =
+  Set.union (gen_live i) (kill_live i)
 
-   let regalloc_fun (f: linear_fun) (live_in, live_out) all_colors =
-   (Hashtbl.create 0, 0)
+let regs_in_instr_list (l: rtl_instr list) : reg Set.t =
+  List.fold_left
+    (fun acc i -> Set.union acc (regs_in_instr i))
+    Set.empty l
 
+let regalloc_on_stack_fun (f: linear_fun) : ((reg, loc) Hashtbl.t * int)=
+  let allocation = Hashtbl.create 10 in
+  let regs = regs_in_instr_list f.linearfunbody in
+  let next_stack_slot =
+    List.fold_left (fun next_stack_slot r ->
+        Hashtbl.replace allocation r (Stk (next_stack_slot));
+        next_stack_slot - 1
+      ) 0 (Set.to_list regs) in
+  (allocation, next_stack_slot)
 
-let regalloc lp lives all_colors =
-  let allocations =
-    Hashtbl.create 17 in
 
+(* Nous allons maintenant construire un graphe d'interférence de registres
+   (register interference graph, ou rig). Le type d'un rig est donné par le type
+   OCaml [(reg, reg Set.t) Hashtbl.t], i.e. une table dont les clés sont des
+   registres et les valeurs sont des ensembles de registres qui "interfèrent"
+   avec le registre-clé. Cela correspond à la relation d'adjacence dans le
+   graphe d'interférence. *)
+
+(* La fonction [add_to_interf rig x y] ajoute [y] à la liste des registres qui
+   interfèrent avec [x] dans le graphe [rig].
+
+   On pourra utiliser la fonction [Hashtbl.modify_def] qui permet de modifier la
+   valeur associée à une clé.
+
+   Par exemple, l'appel [Hashtbl.modify_def def k f rig] modifie la valeur
+   associée à la clé [k] dans le graphe [rig].
+
+   [f] est une fonction qui prend en entrée l'ancienne valeur, et qui retourne
+   la nouvelle valeur (type ['b -> 'b], si [rig] est de type [('a,'b)
+   Hashtbl.t], i.e. ['b] est le type des valeurs).
+
+   [def] est la valeur par défaut donnée à [f] s'il n'existe pas d'ancienne
+   valeur pour la clé [k].
+
+   Attention, les interférences doivent exister dans les deux sens, i.e. si [x]
+   est dans la liste d'interférence de [y], alors [y] doit être dans la liste
+   d'interférence de [x].
+
+*)
+
+let add_interf (rig : (reg, reg Set.t) Hashtbl.t) (x: reg) (y: reg) : unit =
+    (* TODO *)
+    ()
+
+
+(* [make_interf_live rig live] ajoute des arcs dans le graphe d'interférence
+   pour chaque paire de registres vivants en même temps à un point de programme.
+   *)
+let make_interf_live
+    (rig: (reg, reg Set.t) Hashtbl.t)
+    (live : (int, reg Set.t) Hashtbl.t) : unit =
+    (* TODO *)
+   ()
+
+(* [build_interference_graph live_out] construit, en utilisant les fonctions que
+   vous avez écrites, le graphe d'interférence en fonction de la vivacité des
+   variables à la sortie des nœuds donné par [live_out].
+
+   Offert par la maison !
+*)
+let build_interference_graph (live_out : (int, reg Set.t) Hashtbl.t) : (reg, reg Set.t) Hashtbl.t  =
+  let interf = Hashtbl.create 17 in
+  (* On ajoute un sommet pour chaque variable qui apparaît dans le programme. *)
+  Hashtbl.iter (fun _ s ->
+      Set.iter (fun v -> Hashtbl.replace interf v Set.empty) s
+    ) live_out;
+  make_interf_live interf live_out;
+  interf
+
+(* [remove_from_rig rig v] supprime le sommet [v] du graphe d'interférences
+   [rig]. *)
+let remove_from_rig (rig : (reg, reg Set.t) Hashtbl.t)  (v: reg) : unit =
+   (* TODO *)
+   ()
+
+
+(* Type représentant les différentes décisions qui peuvent être prises par
+   l'allocateur de registres.
+
+   - [Spill r] signifie que le pseudo-registre [r] sera évincé (spillé) sur la pile.
+    
+   - [NoSpill r] signifie que le pseudo-registre [r] sera alloué dans un vrai
+   registre physique.
+*)
+type regalloc_decision =
+    Spill of reg
+  | NoSpill of reg
+
+(* Rappel de l'algorithme d'empilement des registres *)
+
+(* Une fois le graphe d'interférences construit, il nous faut parcourir ce
+   graphe afin de le colorer, avec [n] couleurs. On construit une pile de
+   [regalloc_decision].
+
+   Tant que le graphe n'est pas vide:
+
+   - choisir un sommet [s] avec strictement moins de [n] voisins (ce sera le
+   travail de la fonction [pick_node_with_fewer_than_n_neighbors]), empiler la
+   décision [NoSpill s] et retirer [s] du graphe.
+
+   - si aucun tel sommet n'existe dans le graphe, choisir un sommet [s]
+   correspondant à un registre que l'on évincera (ce sera le travail de la
+   fonction [pick_spilling_candidate]). Empiler la décision [Spill s] et retirer
+   [s] du graphe.
+
+*)
+
+(* [pick_node_with_fewer_than_n_neighbors rig n] choisit un nœud du graphe [rig]
+   possédant strictement moins de [n] voisins. Retourne [None] si aucun sommet
+   ne satisfait cette condition. *)
+let pick_node_with_fewer_than_n_neighbors (rig : (reg, reg Set.t) Hashtbl.t) (n: int) : reg option =
+   (* TODO *)
+   None
+
+(* Lorsque la fonction précédente échoue (i.e. aucun sommet n'a moins de [n]
+   voisins), on choisit un pseudo-registre à évincer.
+
+   Une heuristique possible consiste à évincer le pseudo-registre qui a le plus
+   de voisins dans le graphe [rig].
+
+   [pick_spilling_candidate rig] retourne donc le pseudo-registre [r] qui a le
+   plus de voisins dans [rig], ou [None] si [rig] est vide. *)
+let pick_spilling_candidate (rig : (reg, reg Set.t) Hashtbl.t)  : reg option =
+   (* TODO *)
+   None
+
+(* [make_stack rig stack ncolors] construit la pile, selon l'algorithme vu en
+   cours (slides 60 à 63 du cours "Allocation de registres - Autres slides"
+   présent sur Edunao.) *)
+let rec make_stack (rig : (reg, reg Set.t) Hashtbl.t)  (stack : regalloc_decision list) (ncolors: int) : regalloc_decision list =
+   (* TODO *)
+   stack
+
+(* Maintenant que nous avons une pile de [regalloc_decision], il est temps de
+   colorer notre graphe, i.e. associer une couleur (un numéro de registre
+   physique) à chaque pseudo-registre. Nous allons parcourir la pile et pour
+   chaque décision :
+
+   -  [Spill r] : associer un emplacement sur la pile au pseudo-registre [r]. On
+   choisira l'emplacement [next_stack_slot].
+
+   - [NoSpill r] : associer une couleur (un registre) physique au
+   pseudo-registre [r]. On choisira une couleur qui n'est pas déjà associée à un
+   voisin de [r] dans [rig].
+
+   Cette fonction prend en entrée :
+
+   - [allocation] : l'allocation courante, que l'on mettra à jour, et qui
+   permettra de trouver les couleurs qui ne sont pas déjà associées à des
+   voisins.
+
+   - [rig] : le graphe d'interférence, qui permettra de connaître les voisins
+   d'un registre.
+
+   - [all_colors] : l'ensemble des couleurs que l'on peut allouer.
+
+   - [next_stack_slot] : le prochain emplacement disponible sur la pile. Cela
+   représentera des offsets négatifs par rapport à fp, on le mettra donc à jour
+   en décrémentant cette valeur de 1.
+
+   - [decision] : une décision parmi celles empilées.
+
+   Cette fonction met à jour [allocation] et renvoie la nouvelle valeur de
+   [next_stack_slot].
+
+*)
+let allocate (allocation: (reg, loc) Hashtbl.t) (rig: (reg, reg Set.t) Hashtbl.t)
+    (all_colors: int Set.t)
+    (next_stack_slot: int) (decision: regalloc_decision)
+  : int =
+   (* TODO *)
+   next_stack_slot
+
+(* [regalloc_fun f live_out all_colors] effectue l'allocation de registres pour
+   la fonction [f].
+
+   - [live_out] est un mapping des numéros d'instructions dans la fonction
+   Linear vers l'ensemble des registres vivants après cette instruction.
+
+   - [all_colors] est l'ensemble des registres que l'on pourra utiliser.
+
+   Cette fonction renvoie un triplet [(rig, allocation, next_stack_slot)] :
+
+   - [rig] est le graphe d'interférences (simplement pour l'affichage)
+
+   - [allocation] est l'allocation de registre que vous aurez construit
+
+   - [next_stack_slot] est le prochain emplacement disponible sur la pile
+   (utilisé dans [ltl_gen], qui vous est fourni.)
+*)
+let regalloc_fun (f: linear_fun)
+    (live_out: (int, reg Set.t) Hashtbl.t)
+    (all_colors: int Set.t) :
+  (reg, reg Set.t) Hashtbl.t      (* the RIG *)
+  * (reg, loc) Hashtbl.t          (* the allocation *)
+  * int                         (* the next stack slot *)
+  =
+  let rig = build_interference_graph live_out in
+  let allocation = Hashtbl.create 17 in
+  (* Les pseudo-registres qui contiennent les arguments sont traités séparément
+     dans [ltl_gen.ml]. On les enlève donc du graphe. *)
+  List.iter (fun p -> remove_from_rig rig p) f.linearfunargs;
+  (* On effectue une copie [g] du graphe d'interférence [rig]. En effet, comme
+     on va supprimer des sommets du graphe, on perd l'information
+     d'interférence, dont on aura besoin pour effectuer la coloration. *)
+  let g = Hashtbl.copy rig in
+  let stack = make_stack g [] (Set.cardinal all_colors) in
+  let next_stack_slot =
+    List.fold_left (fun next_stack_slot decision ->
+        allocate allocation rig all_colors next_stack_slot decision
+      ) 0 stack in
+  (rig, allocation, next_stack_slot)
+
+
+(* [dump_interf_graph fname rig] affiche les interférences associées à chaque
+   registre. Peut être utile pour le débogage ! Pas besoin d'inspecter cette
+   fonction, à moins qu'elle soit buggée... :-) *)
+let dump_interf_graph oc (fname, rig, allocation) =
+  let colors = Array.of_list [
+      "blue"; "red"; "orange"; "pink"; "green"; "purple";
+      "brown"; "turquoise"; "gray"; "gold"; "darkorchid"; "bisque";
+      "darkseagreen"; "cornsilk"; "burlywood"; "dodgerblue"; "antiquewhite"; "firebrick";
+      "deepskyblue"; "darkolivegreen"; "hotpink"; "lightsalmon"; "magenta"; "lawngreen";
+    ] in
+  let color_of_allocation r =
+    match Hashtbl.find_option allocation r with
+    | Some (Reg r) ->
+      Array.get colors (r mod Array.length colors)
+    | _ -> "white"
+  in
+  Format.fprintf oc "subgraph cluster_%s{\n" fname;
+  Format.fprintf oc "label=\"%s\";\n" fname;
+  Hashtbl.keys rig |> Enum.iter (fun r ->
+      Format.fprintf oc "r%d [style=filled,fillcolor=\"%s\"];\n" r (color_of_allocation r)
+    );
+  Hashtbl.iter
+    (fun i s ->
+       Set.iter (fun x ->
+           Format.fprintf oc "r%d -> r%d;\n" i x
+         ) s;)
+    rig;
+  Format.fprintf oc "}\n"
+
+let dump_interf_graphs oc allocations =
+  Format.fprintf oc "digraph RIGS {\n";
+  Hashtbl.iter (fun fname (rig, allocation, next_stack_slot) ->
+      dump_interf_graph oc (fname, rig, allocation)
+    ) allocations;
+  Format.fprintf oc "}\n"
+
+(* On applique l'allocation de registres à tout le programme Linear, et on
+   affiche tout ça dans le rapport (la page HTML de chaque fichier). *)
+let regalloc lp lives all_colors =
+  let allocations = Hashtbl.create 17 in
   List.iter (function (fname,Gfun f) ->
       begin match Hashtbl.find_option lives fname with
       | Some (live_in, live_out) ->
-        let (allocation, curstackslot) = regalloc_fun f (live_in, live_out) all_colors in
-        Hashtbl.replace allocations fname (allocation, curstackslot)
+        let (rig, allocation, curstackslot) =
+          if !Options.naive_regalloc
+          then let (al, nss) = regalloc_on_stack_fun f in
+            (Hashtbl.create 0, al, nss)
+          else regalloc_fun f live_out all_colors
+        in
+        Hashtbl.replace allocations fname (rig, allocation, curstackslot)
       | None -> ()
       end
     ) lp;
+  dump !Options.rig_dump dump_interf_graphs allocations
+    (call_dot "regalloc" "Register Allocation");
   allocations
diff --git a/src/report.ml b/src/report.ml
index 8c2d2281654805228eb2bc096affc3759df4e2c9..b60bb9c5a854c1b56c1ae7bba4906d8c5cb27730 100644
--- a/src/report.ml
+++ b/src/report.ml
@@ -37,3 +37,11 @@ let make_report filename report () =
     !report;
   close_out html;
   ()
+
+let call_dot report_sectid report_secttitle file () : unit =
+  if not !Options.no_dot
+  then begin
+    let r = Sys.command (Format.sprintf "dot -Tsvg %s -o %s.svg" file file) in
+    add_to_report report_sectid report_secttitle (Img (Filename.basename file^".svg"));
+    ignore r
+  end
diff --git a/src/riscv.ml b/src/riscv.ml
index b4f85ae85b9296e34a93f26ff7e31fae07a3b29a..ca9dd36e550739e238720ef82273f8d55361d74e 100644
--- a/src/riscv.ml
+++ b/src/riscv.ml
@@ -58,52 +58,100 @@ let print_unop (u: unop) =
 
 let instrsuffix_of_size sz =
   match !Archi.archi, sz with
-  | _, 1 -> 'b'
-  | _, 4 -> 'w'
-  | A64, 8 -> 'd'
+  | _, 1 -> OK 'b'
+  | _, 4 -> OK 'w'
+  | A64, 8 -> OK 'd'
   | _, _ ->
-    failwith (Format.sprintf "Impossible write size (%d) in archi (%d)"
+    Error (Format.sprintf "Impossible write size (%d) in archi (%d)"
                 sz !Archi.nbits)
 
 let dump_riscv_instr oc (i: ltl_instr) =
   match i with
   | LAddi(rd, rs, i) ->
-    Format.fprintf oc "addi %s, %s, %d\n" (print_reg rd) (print_reg rs) i
+    Format.fprintf oc "addi %s, %s, %d\n" (print_reg rd) (print_reg rs) i;
+    OK ()
   | LSubi(rd, rs, i) ->
-    Format.fprintf oc "addi %s, %s, %d\n" (print_reg rd) (print_reg rs) (-i)
+    Format.fprintf oc "addi %s, %s, %d\n" (print_reg rd) (print_reg rs) (-i);
+    OK ()
   | LBinop(b, rd, rs1, rs2) ->
-     (* TODO *)
-     Format.fprintf oc "%s %s, %s, %s\n"
-               (print_binop b) (print_reg rd) (print_reg rs1) (print_reg rs2)
+    begin match b with
+      | Elang.Eclt ->
+        Format.fprintf oc "slt %s, %s, %s\n"
+          (print_reg rd) (print_reg rs1) (print_reg rs2);
+        OK ()
+      | Elang.Ecgt ->
+        Format.fprintf oc "slt %s, %s, %s\n"
+          (print_reg rd) (print_reg rs2) (print_reg rs1);
+        OK ()
+      | Elang.Ecle ->
+        (* 'rd <- rs1 <= rs2' == 'rd <- rs2 < rs1; rd <- not rd' *)
+        Format.fprintf oc "slt %s, %s, %s\n"
+          (print_reg rd) (print_reg rs2) (print_reg rs1);
+        Format.fprintf oc "not %s, %s\n"
+          (print_reg rd) (print_reg rd);
+        OK ()
+      | Elang.Ecge ->
+        Format.fprintf oc "slt %s, %s, %s\n"
+          (print_reg rd) (print_reg rs1) (print_reg rs2);
+        Format.fprintf oc "not %s, %s\n"
+          (print_reg rd) (print_reg rd);
+        OK ()
+      | Elang.Eceq ->
+        Format.fprintf oc "sub %s, %s, %s\n"
+          (print_reg rd) (print_reg rs1) (print_reg rs2);
+        Format.fprintf oc "seqz %s, %s\n"
+          (print_reg rd) (print_reg rd);
+        OK ()
+      | Elang.Ecne ->
+        Format.fprintf oc "sub %s, %s, %s\n"
+          (print_reg rd) (print_reg rs1) (print_reg rs2);
+        Format.fprintf oc "snez %s, %s\n"
+          (print_reg rd) (print_reg rd);
+        OK ()
+      | _ -> Format.fprintf oc "%s %s, %s, %s\n"
+               (print_binop b) (print_reg rd) (print_reg rs1) (print_reg rs2);
+        OK ()
+    end
   | LUnop(u, rd, rs) ->
     Format.fprintf oc "%s %s, %s\n"
-      (print_unop u) (print_reg rd) (print_reg rs)
+          (print_unop u) (print_reg rd) (print_reg rs); OK ()
   | LStore(rt, i, rs, sz) ->
-    Format.fprintf oc "s%c %s, %d(%s)\n"
-      (instrsuffix_of_size sz) (print_reg rs) i (print_reg rt)
+    (instrsuffix_of_size sz) >>= fun sz ->
+    OK (Format.fprintf oc "s%c %s, %d(%s)\n"
+          sz (print_reg rs) i (print_reg rt))
   | LLoad(rd, rt, i, sz) ->
+    (instrsuffix_of_size sz) >>= fun sz ->
     Format.fprintf oc "l%c %s, %d(%s)\n"
-      (instrsuffix_of_size sz) (print_reg rd) i (print_reg rt)
+      sz (print_reg rd) i (print_reg rt); OK ()
   | LMov(rd, rs) ->
-    Format.fprintf oc "mv %s, %s\n" (print_reg rd) (print_reg rs)
+    Format.fprintf oc "mv %s, %s\n" (print_reg rd) (print_reg rs);
+    OK ()
   | LLabel l ->
-    Format.fprintf oc "%s:\n" l
-  | LJmp l -> Format.fprintf oc "j %s\n" l
-  | LJmpr r -> Format.fprintf oc "jr %s\n" (print_reg r)
-  | LConst (rd, i) -> Format.fprintf oc "li %s, %d\n\n" (print_reg rd) i
-  | LComment l -> Format.fprintf oc "# %s\n" l
+    Format.fprintf oc "%s:\n" l;
+    OK ()
+  | LJmp l -> Format.fprintf oc "j %s\n" l;
+    OK ()
+  | LJmpr r -> Format.fprintf oc "jr %s\n" (print_reg r);
+    OK ()
+  | LConst (rd, i) -> Format.fprintf oc "li %s, %d\n\n" (print_reg rd) i;
+    OK ()
+  | LComment l -> Format.fprintf oc "# %s\n" l;
+    OK ()
   | LBranch(cmp, rs1, rs2, s) ->
     Format.fprintf oc "%s %s, %s, %s\n"
-      (riscv_of_cmp cmp) (print_reg rs1) (print_reg rs2) s
+      (riscv_of_cmp cmp) (print_reg rs1) (print_reg rs2) s;
+    OK ()
   | LCall fname ->
-    Format.fprintf oc "jal ra, %s\n" fname
-  | LHalt -> Format.fprintf oc "halt\n"
+    Format.fprintf oc "jal ra, %s\n" fname;
+    OK ()
+  | LHalt -> Format.fprintf oc "halt\n";
+    OK ()
 
 let dump_riscv_fun oc (fname , lf) =
   Format.fprintf oc "%s:\n" fname;
-  List.iter (dump_riscv_instr oc) lf.ltlfunbody
+  list_iter_res (dump_riscv_instr oc) lf.ltlfunbody
 
-let riscv_load_args oc =
+let riscv_load_args oc : unit res =
   let nargs = [1;2;3;4;5;6;7;8] in
   (* for each arg in [1..8]:
        a0 <- arg
@@ -126,7 +174,7 @@ let riscv_load_args oc =
            List.map (fun i ->
                [LLoad(starting_arg_register + i - 1, reg_fp,
                       - !Archi.wordsize*i, !Archi.wordsize)]) in
-  (l1 @ l2) |> List.concat |> List.iter (fun i -> dump_riscv_instr oc i)
+  (l1 @ l2) |> List.concat |> list_iter_res (fun i -> dump_riscv_instr oc i)
 
 
 let riscv_fun_load_arg oc () =
@@ -163,7 +211,7 @@ let riscv_prelude oc =
   Format.fprintf oc "  %s t0, 0(gp)\n" (rv_store ());
   Format.fprintf oc "  mv s0, sp\n";
   Format.fprintf oc "  add sp, sp, -72\n";
-  riscv_load_args oc;
+  riscv_load_args oc >>= fun _ -> 
   Format.fprintf oc "jal ra, main\n";
   Format.fprintf oc "mv s0, a0\n";
   Format.fprintf oc "jal ra, println\n";
@@ -171,12 +219,13 @@ let riscv_prelude oc =
   Format.fprintf oc "jal ra, print_int\n";
   Format.fprintf oc "jal ra, println\n";
   Format.fprintf oc "addi a7, zero, 93\n";
-  Format.fprintf oc "ecall\n"
+  Format.fprintf oc "ecall\n";
+  OK ()
 
-let dump_riscv_prog oc lp =
-  if !nostart then () else riscv_prelude oc;
+let dump_riscv_prog oc lp : unit res =
+  if !nostart then OK () else riscv_prelude oc >>= fun _ ->
   Format.fprintf oc ".global main\n";
-  List.iter (function
+  list_iter_res (function
         (fname, Gfun f) -> dump_riscv_fun oc (fname,f)
-    ) lp;
+    ) lp >>= fun _ ->
   riscv_fun_load_arg oc ()
diff --git a/src/rtl_print.ml b/src/rtl_print.ml
index 15d4ca117fdee3127656c0d86caccf18d8794d8c..c8ed813944d2722f5266a043b1af819e2d321860 100644
--- a/src/rtl_print.ml
+++ b/src/rtl_print.ml
@@ -19,6 +19,13 @@ let print_cmpop (r: rtl_cmp) =
 
 let dump_rtl_instr name (live_in, live_out) oc (i: rtl_instr) =
   let print_node s = Format.sprintf "%s_%d" name s in
+
+  let dump_liveness live where =
+    match live with
+      Some live -> Format.fprintf oc "// Live %s : { %s }\n" where (String.concat ", " (Set.to_list (Set.map string_of_int live)))
+    | None -> ()
+  in
+  dump_liveness live_in "before";
   begin match i with
   | Rbinop (b, rd, rs1, rs2) ->
     Format.fprintf oc "%s <- %s(%s, %s)" (print_reg rd) (dump_binop b) (print_reg rs1) (print_reg rs2)
@@ -35,7 +42,8 @@ let dump_rtl_instr name (live_in, live_out) oc (i: rtl_instr) =
   | Rprint r -> Format.fprintf oc "print %s" (print_reg r)
   | Rlabel n -> Format.fprintf oc "%s_%d:" name n
   end;
-  Format.fprintf oc "\n"
+  Format.fprintf oc "\n";
+  dump_liveness live_out "after"
 
 let dump_rtl_node name lives =
   print_listi (fun i ->
diff --git a/src/utils.ml b/src/utils.ml
index 3b1b122340e4ba34b0e8abe98c26e4a55ba80196..f77987931e59a1b128afee4223dfeb4d7776b9c3 100644
--- a/src/utils.ml
+++ b/src/utils.ml
@@ -246,6 +246,21 @@ let list_map_res f l =
       OK (acc@[e])
     ) (OK []) l
 
+
+let list_map_resi f l =
+  List.fold_lefti (fun acc i e ->
+      acc >>= fun acc ->
+      f i e >>= fun e ->
+      OK (acc@[e])
+    ) (OK []) l
+
+let rec list_iter_res f l =
+  match l with
+    [] -> OK ()
+  | a::r ->
+    f a >>= fun  _ ->
+    list_iter_res f r
+
 let assoc_err ?word:(word="item") k l =
   match List.assoc_opt k l with
   | Some v -> OK v
@@ -286,3 +301,19 @@ let string_of_int_option v =
   match v with
   | None -> "undef"
   | Some x -> string_of_int x
+
+
+let dump file (dumpf : _ -> 'a -> unit) (p: 'a) (additional_command: string -> unit -> unit) =
+  begin match file with
+    | None -> ()
+    | Some file ->
+      let oc, close = 
+        if file = "-"
+        then (Format.std_formatter, fun _ -> ())
+        else
+          let oc = open_out file in
+          (Format.formatter_of_out_channel oc, fun () -> close_out oc)
+      in
+      dumpf oc p; close ();
+      if file <> "-" then additional_command file ()
+  end
diff --git a/tests/Makefile b/tests/Makefile
index b740fda1fe88bd18652f50caedd20faf247bd4b6..1169a467d9d8cd7129f7bd2876692dbbdbe879ea 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -8,9 +8,5 @@ all: ../main.native
 	./test.py $(OPTS)
 
 clean:
-	find . -name *.ltl -or -name *.cfg -or -name *.exe -or -name *.s -or -name		\
-	*.rtl -or -name *.ast -or -name *.cfg0 -or -name *.cfg1 -or -name *.cfg2 -or	\
-	-name *.riscv -or -name *.dump -or -name *.linear1 -or -name *.linear -or			\
-	-name *.html -or -name *.svg -or -name *.html -or -name *.lex | xargs -I{} rm	\
-	{}
+	find . -name '*.ltl' -or -name '*.cfg' -or -name '*.exe' -or -name '*.s' -or -name '*.rtl' -or -name '*.ast' -or -name '*.cfg0' -or -name '*.cfg1' -or -name '*.cfg2' -or -name '*.cfg3' -or -name '*.riscv' -or -name '*.dump' -or	-name '*.linear1' -or -name '*.linear' -or -name '*.html' -or -name '*.svg'	-or -name '*.html' -or -name '*.lex' -or -name "*.json" | xargs -I{} rm {}
 	rm -rf __pycache__
diff --git a/tests/basic/arg-test.e b/tests/basic/arg-test.e
new file mode 100644
index 0000000000000000000000000000000000000000..a265d644923b1ca6ded782d8faeb94756d90c0f6
--- /dev/null
+++ b/tests/basic/arg-test.e
@@ -0,0 +1,14 @@
+main(n, m){
+  a = 10;
+  b = 20;
+  if (3 > n){
+    x = a;
+  } else {
+    x = b;
+  }
+  return x;
+}
+f(x){
+  n = 3;
+  return 3 * x;
+}
diff --git a/tests/basic/arg-test.e.expect_14_12_3_8_12 b/tests/basic/arg-test.e.expect_14_12_3_8_12
new file mode 100644
index 0000000000000000000000000000000000000000..4de51e4d38522a71a09ab4c411d09d99f1e80932
--- /dev/null
+++ b/tests/basic/arg-test.e.expect_14_12_3_8_12
@@ -0,0 +1 @@
+{"output": "", "error": null, "retval": 20}
\ No newline at end of file
diff --git a/tests/basic/arg-test.e.expect_1_2_3 b/tests/basic/arg-test.e.expect_1_2_3
new file mode 100644
index 0000000000000000000000000000000000000000..4de51e4d38522a71a09ab4c411d09d99f1e80932
--- /dev/null
+++ b/tests/basic/arg-test.e.expect_1_2_3
@@ -0,0 +1 @@
+{"output": "", "error": null, "retval": 20}
\ No newline at end of file
diff --git a/tests/basic/lots-of-regs.e b/tests/basic/lots-of-regs.e
new file mode 100644
index 0000000000000000000000000000000000000000..2495c7855016762430ba4f6927e798d036f0f723
--- /dev/null
+++ b/tests/basic/lots-of-regs.e
@@ -0,0 +1,21 @@
+main(a, b){
+  x = a;
+  y = b;
+  z = a * b;
+  t = a + b + z;
+  u = z - 3;
+  v = x - u;
+  w = a * x + z - t;
+  i = 35;
+  j = i * w;
+  k = 8 * t + z / i;
+  l = 19 * k;
+  m = 12;
+  n = 12;
+  o = 12;
+  p = 12;
+  q = 12;
+  r = 12;
+  s = 12;
+  return x + y + z + t + u + v + w + i + j + k + l + m + n + o + p + q + r + s;
+}
diff --git a/tests/basic/lots-of-regs.e.expect_14_12_3_8_12 b/tests/basic/lots-of-regs.e.expect_14_12_3_8_12
new file mode 100644
index 0000000000000000000000000000000000000000..36bc30ad8e3a677ef8d97fda646b7d615463399b
--- /dev/null
+++ b/tests/basic/lots-of-regs.e.expect_14_12_3_8_12
@@ -0,0 +1 @@
+{"output": "", "error": null, "retval": 37761}
\ No newline at end of file
diff --git a/tests/basic/lots-of-regs.e.expect_1_2_3 b/tests/basic/lots-of-regs.e.expect_1_2_3
new file mode 100644
index 0000000000000000000000000000000000000000..0f7c0dd6058a095a430101f739d92a8259ed714c
--- /dev/null
+++ b/tests/basic/lots-of-regs.e.expect_1_2_3
@@ -0,0 +1 @@
+{"output": "", "error": null, "retval": 858}
\ No newline at end of file