mips-cc

A little C compiler
git clone git@git.mpah.dev/mips-cc.git
Log | Files | Refs | README

compiler.ml (4334B)


      1 open Mips
      2 open Ast.IR2
      3 
      4 module Env = Map.Make(String)
      5 
      6 type cinfo = { code: Mips.instr list
      7              ; env: Mips.loc Env.t
      8              ; fpo: int
      9              ; counter: int
     10              ; return: string }
     11 
     12 let rec compile_expr e env =
     13   match e with
     14 (*   | Value v -> compile_value v *)
     15   | Data l  -> [ La (V0, Lbl (l)) ]
     16   | Bool b  -> [ Li (V0, if b then 1 else 0) ]
     17   | Nil     -> [ Li (V0, 0) ]
     18   | Int n   -> [ Li (V0, n) ]
     19   | Float f -> [ Lis (F0, f) ]
     20   | Char c  -> [ Li (V0, (int_of_char c)) ]
     21   | Var v   -> [ Lw (V0, Env.find v env) ]
     22   | Call (f, args) ->
     23      let ca = List.map (fun a ->
     24                   compile_expr a env
     25                   @ [ Addi (SP, SP, -4)
     26                     ; Sw (V0, Mem (SP, 0)) ])
     27                 args in
     28      List.flatten ca
     29      @ [ Jal f
     30        ; Addi (SP, SP, 4 * (List.length args)) ]
     31 
     32 let rec compile_instr i info =
     33   match i with
     34   | Decl v ->
     35      { info with
     36        env = Env.add v (Mem (FP, -info.fpo)) info.env
     37      ; fpo = info.fpo + 4 }
     38   | Return e ->
     39      { info with
     40        code = info.code
     41               @ compile_expr e info.env
     42               @ [ B info.return ] }
     43   | Expr e ->
     44      { info with
     45        code = info.code
     46               @ compile_expr e info.env }
     47 
     48   | Assign (lv, e) ->
     49      { info with
     50        code = (info.code
     51                @ compile_expr e info.env
     52                @
     53                match lv with
     54                | Var v -> [ Sw (V0, Env.find v info.env) ])
     55      }
     56 
     57 (*
     58    TODO
     59   | Assign (lv, e) -> { info with
     60        code = info.code
     61               @ compile_expr e info.env
     62               @ (match lv with
     63                  | LVar  v -> [ Sw (V0, Env.find v info.env) ]
     64                  | LAddr a -> []
     65                               @ [ Addi (SP, SP, -4)
     66                                 ; Sw (V0, Mem (SP, 0)) ]
     67                               @ compile_expr a info.env
     68                               @ [ Lw (T0, Mem (SP, 0))
     69                                 ; Addi (SP, SP, 4)
     70                                 ; Sw (T0, Mem (V0, 0)) ]) }
     71 *)
     72   | Loop (c, t) ->
     73      let uniq = string_of_int info.counter in
     74      let ct = compile_block t { info with code = []
     75                                         ; counter = info.counter + 1 } in
     76      { info with
     77        code = info.code
     78               @ [ Label ("startloop" ^ uniq) ]
     79               @ compile_expr c info.env
     80               @ [ Beqz (V0, "endloop" ^ uniq) ]
     81               @ ct.code
     82               @ [ B ("startloop" ^ uniq) ]
     83               @ [ Label ("endloop" ^ uniq) ]
     84      ; counter = ct.counter }
     85 
     86   | Cond (c, t, e) ->
     87      let uniq = string_of_int info.counter in
     88      let ct = compile_block t { info with code = []
     89                                         ; counter = info.counter + 1 } in
     90      let ce = compile_block e { info with code = []
     91                                         ; counter = ct.counter } in
     92      { info with
     93        code = info.code
     94               @ compile_expr c info.env
     95               @ [ Beqz (V0, "else" ^ uniq) ]
     96               @ ct.code
     97               @ [ B ("endif" ^ uniq)
     98                 ; Label ("else" ^ uniq) ]
     99               @ ce.code
    100               @ [ Label ("endif" ^ uniq) ]
    101      ; counter = ce.counter }
    102 
    103 and compile_block b info =
    104   match b with
    105   | [] -> info
    106   | i :: r ->
    107      compile_block r (compile_instr i info)
    108 
    109 let compile_def (Func (name, args, b)) counter =
    110   let cb = compile_block b
    111              { code = []
    112              ; env =  List.fold_left
    113                         (fun e (i, a) -> Env.add a (Mem (FP, 4 * i)) e)
    114                         Env.empty (List.mapi (fun i a -> i + 1, a) args)
    115              ; fpo = 8
    116              ; counter = counter + 1
    117              ; return = "ret" ^ (string_of_int counter) }
    118   in cb.counter,
    119      []
    120      @ [ Label name
    121        ; Addi (SP, SP, -cb.fpo)
    122        ; Sw (RA, Mem (SP, cb.fpo - 4))
    123        ; Sw (FP, Mem (SP, cb.fpo - 8))
    124        ; Addi (FP, SP, cb.fpo - 4) ]
    125      @ cb.code
    126      @ [ Label cb.return
    127        ; Addi (SP, SP, cb.fpo)
    128        ; Lw (RA, Mem (FP, 0))
    129        ; Lw (FP, Mem (FP, -4))
    130        ; Jr (RA) ]
    131 
    132 let rec compile_prog p counter =
    133   match p with
    134   | [] -> []
    135   | d :: r ->
    136      let new_counter, cd = compile_def d counter in
    137      cd @ (compile_prog r new_counter)
    138 
    139 let compile (code, data) =
    140   { text = Baselib.builtins @ compile_prog code 0
    141   ; data = List.map (fun (l, s) -> (l, Asciiz s)) data }