2022-12-10 17:51:31 +01:00
open Ast . IR2
open Ast . V2
2022-12-06 20:39:15 +01:00
open Mips
2022-12-10 17:51:31 +01:00
open Baselib
2022-12-06 20:39:15 +01:00
2022-12-08 19:55:22 +01:00
type info =
{ asm : instr list
; env : loc Env . t
; fpo : int (* FP offset *)
2022-12-09 14:14:33 +01:00
; cnt : int (* Counter *)
; ret : string (* Return *)
2022-12-08 19:55:22 +01:00
}
2022-12-13 15:00:39 +01:00
let puf = " f_ " (* prefix user function *)
2022-12-08 14:04:46 +01:00
let compile_value = function
2022-12-09 22:20:05 +01:00
| Void -> [ Li ( V0 , 0 ) ]
2022-12-06 22:22:48 +01:00
| Int n -> [ Li ( V0 , n ) ]
2022-12-08 21:30:39 +01:00
| Bool b -> [ Li ( V0 , if b then 1 else 0 ) ]
2022-12-11 03:35:52 +01:00
| Data l -> [ La ( V0 , Lbl l ) ]
2022-12-06 22:22:48 +01:00
;;
2022-12-06 20:39:15 +01:00
2022-12-09 14:45:59 +01:00
let rec compile_expr env = function
2022-12-08 14:04:46 +01:00
| Val v -> compile_value v
2022-12-08 19:55:22 +01:00
| Var v -> [ Lw ( V0 , Env . find v env ) ]
2022-12-09 14:45:59 +01:00
| Call ( f , args ) ->
2022-12-27 17:07:24 +01:00
let compiled_args =
2022-12-09 14:45:59 +01:00
List . map
( fun a -> compile_expr env a @ [ Addi ( SP , SP , - 4 ) ; Sw ( V0 , Mem ( SP , 0 ) ) ] )
args
in
2022-12-27 17:07:24 +01:00
List . flatten compiled_args
2022-12-23 06:40:40 +01:00
@ ( if Env . mem f Baselib . builtins
then Env . find f Baselib . builtins
else [ Jal ( puf ^ f ) ] )
@ [ Addi ( SP , SP , 4 * List . length args ) ]
2022-12-08 19:55:22 +01:00
;;
2022-12-13 16:09:25 +01:00
let rec compile_instr info = function
2022-12-08 19:55:22 +01:00
| 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 ) ]
}
2022-12-13 16:09:25 +01:00
| 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
}
2022-12-13 17:10:14 +01:00
| 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
2022-12-22 16:44:00 +01:00
@ [ B ( " while " ^ uniq ) ]
2022-12-13 17:10:14 +01:00
@ [ Label ( " endwhile " ^ uniq ) ]
; cnt = cb . cnt
}
2022-12-10 01:55:15 +01:00
| Do e -> { info with asm = info . asm @ compile_expr info . env e }
2022-12-09 14:14:33 +01:00
| Return e -> { info with asm = info . asm @ compile_expr info . env e @ [ B info . ret ] }
2022-12-08 19:55:22 +01:00
2022-12-13 16:09:25 +01:00
and compile_block info = function
2022-12-08 19:55:22 +01:00
| [] -> info
| i :: b -> compile_block ( compile_instr info i ) b
;;
2022-12-10 01:55:15 +01:00
let compile_def ( Func ( name , args , body ) ) counter =
2022-12-09 14:14:33 +01:00
let compiled =
compile_block
{ asm = []
2022-12-10 15:17:40 +01:00
; 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 ) )
2022-12-09 14:14:33 +01:00
; fpo = 8
; cnt = counter + 1
; ret = " ret " ^ string_of_int counter
}
body
in
2022-12-13 15:00:39 +01:00
let lbl_puf = if name = " main " then " " else puf in
2022-12-10 01:55:15 +01:00
( compiled . cnt
2022-12-13 15:00:39 +01:00
, [ Label ( lbl_puf ^ name )
2022-12-10 01:55:15 +01:00
; 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 )
2022-12-09 14:14:33 +01:00
]
2022-12-10 01:55:15 +01:00
@ 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
2022-12-08 14:04:46 +01:00
;;
2022-12-10 17:51:31 +01:00
let compile ( ir , data ) =
2022-12-10 01:55:15 +01:00
let asm = compile_prog 0 ir in
2022-12-10 17:51:31 +01:00
{ text = asm ; data }
2022-12-08 19:55:22 +01:00
;;