This repository has been archived on 2022-12-27. You can view files and clone it, but cannot push or open issues or pull requests.
compilateurMIPS/compiler.ml

125 lines
3.3 KiB
OCaml

open Ast.IR2
open Ast.V2
open Mips
open Baselib
type info =
{ asm : instr list
; env : loc Env.t
; fpo : int (* FP offset *)
; cnt : int (* Counter *)
; ret : string (* Return *)
}
let puf = "f_" (* prefix user function *)
let compile_value = function
| Void -> [ Li (V0, 0) ]
| Int n -> [ Li (V0, n) ]
| Bool b -> [ Li (V0, if b then 1 else 0) ]
| Data l -> [ La (V0, Lbl l) ]
;;
let rec compile_expr env = function
| Val v -> compile_value v
| Var v -> [ Lw (V0, Env.find v env) ]
| Call (f, args) ->
let compiled_args =
List.map
(fun a -> compile_expr env a @ [ Addi (SP, SP, -4); Sw (V0, Mem (SP, 0)) ])
args
in
List.flatten compiled_args
@ (if Env.mem f Baselib.builtins
then Env.find f Baselib.builtins
else [ Jal (puf ^ f) ])
@ [ Addi (SP, SP, 4 * List.length args) ]
;;
let rec compile_instr info = function
| Decl v ->
{ info with env = Env.add v (Mem (FP, -info.fpo)) info.env; fpo = info.fpo + 4 }
| Assign (v, e) ->
{ info with
asm = info.asm @ compile_expr info.env e @ [ Sw (V0, Env.find v info.env) ]
}
| Cond (e, ib, eb) ->
let uniq = string_of_int info.cnt in
let cib = compile_block { info with asm = []; cnt = info.cnt + 1 } ib in
let ceb = compile_block { info with asm = []; cnt = cib.cnt } eb in
{ info with
asm =
info.asm
@ compile_expr info.env e
@ [ Beqz (V0, "else" ^ uniq) ]
@ cib.asm
@ [ B ("endif" ^ uniq); Label ("else" ^ uniq) ]
@ ceb.asm
@ [ Label ("endif" ^ uniq) ]
; cnt = ceb.cnt
}
| Loop (e, b) ->
let uniq = string_of_int info.cnt in
let cb = compile_block { info with asm = []; cnt = info.cnt + 1 } b in
{ info with
asm =
info.asm
@ [ Label ("while" ^ uniq) ]
@ compile_expr info.env e
@ [ Beqz (V0, "endwhile" ^ uniq) ]
@ cb.asm
@ [ B ("while" ^ uniq) ]
@ [ Label ("endwhile" ^ uniq) ]
; cnt = cb.cnt
}
| Do e -> { info with asm = info.asm @ compile_expr info.env e }
| Return e -> { info with asm = info.asm @ compile_expr info.env e @ [ B info.ret ] }
and compile_block info = function
| [] -> info
| i :: b -> compile_block (compile_instr info i) b
;;
let compile_def (Func (name, args, body)) counter =
let compiled =
compile_block
{ asm = []
; env =
List.fold_left
(fun env (arg, addr) -> Env.add arg addr env)
Env.empty
(List.mapi (fun i a -> a, Mem (FP, 4 * (i + 1))) (List.rev args))
; fpo = 8
; cnt = counter + 1
; ret = "ret" ^ string_of_int counter
}
body
in
let lbl_puf = if name = "main" then "" else puf in
( compiled.cnt
, [ Label (lbl_puf ^ name)
; Addi (SP, SP, -compiled.fpo)
; Sw (RA, Mem (SP, compiled.fpo - 4))
; Sw (FP, Mem (SP, compiled.fpo - 8))
; Addi (FP, SP, compiled.fpo - 4)
]
@ compiled.asm
@ [ Label compiled.ret
; Addi (SP, SP, compiled.fpo)
; Lw (RA, Mem (FP, 0))
; Lw (FP, Mem (FP, -4))
; Jr RA
] )
;;
let rec compile_prog counter = function
| [] -> []
| d :: r ->
let new_counter, cd = compile_def d counter in
cd @ compile_prog new_counter r
;;
let compile (ir, data) =
let asm = compile_prog 0 ir in
{ text = asm; data }
;;