-
Wilke Pierre authoredWilke Pierre authored
rtl_run.ml 3.79 KiB
open Batteries
open BatList
open Elang
open Cfg
open Elang_run
open Cfg_run
open Rtl
open Rtl_print
open Utils
open Builtins
open Prog
type state = {
mem: Mem.t;
regs: (reg, int) Hashtbl.t;
}
let init_state memsize =
{
mem = Mem.init memsize;
regs = Hashtbl.create 17
}
let eval_rtl_cmp = function
Rcle -> (<=)
| Rclt -> (<)
| Rcge -> (>=)
| Rcgt -> (>)
| Rceq -> (=)
| Rcne -> (<>)
let rec exec_rtl_instr oc rp rtlfunname f st (i: rtl_instr) =
match i with
| Rbinop (b, rd, rs1, rs2) ->
begin match Hashtbl.find_option st.regs rs1,
Hashtbl.find_option st.regs rs2 with
| Some v1, Some v2 ->
Hashtbl.replace st.regs rd (eval_binop b v1 v2);
OK (None, st)
| _, _ -> Error (Printf.sprintf "Binop applied on undefined registers (%s and %s)" (print_reg rs1) (print_reg rs2))
end
| Runop (u, rd, rs) ->
begin match Hashtbl.find_option st.regs rs with
| Some v ->
Hashtbl.replace st.regs rd (eval_unop u v);
OK (None, st)
| _ -> Error (Printf.sprintf "Unop applied on undefined register %s" (print_reg rs))
end
| Rconst (rd, i) ->
Hashtbl.replace st.regs rd i;
OK (None, st)
| Rbranch (cmp, r1, r2, s1) ->
begin match Hashtbl.find_option st.regs r1,
Hashtbl.find_option st.regs r2 with
| Some v1, Some v2 ->
(if eval_rtl_cmp cmp v1 v2 then exec_rtl_instr_at oc rp rtlfunname f st s1 else OK (None, st))
| _, _ -> Error (Printf.sprintf "Branching on undefined registers (%s and %s)" (print_reg r1) (print_reg r2))
end
| Rjmp s -> exec_rtl_instr_at oc rp rtlfunname f st s
| Rmov (rd, rs) ->
begin match Hashtbl.find_option st.regs rs with
| Some s ->
Hashtbl.replace st.regs rd s;
OK (None, st)
| _ -> Error (Printf.sprintf "Mov on undefined register (%s)" (print_reg rs))
end
| Rret r ->
begin match Hashtbl.find_option st.regs r with
| Some s -> OK (Some s, st)
| _ -> Error (Printf.sprintf "Ret on undefined register (%s)" (print_reg r))
end
| Rprint r ->
begin match Hashtbl.find_option st.regs r with
| Some s ->
Format.fprintf oc "%d\n" s;
OK (None, st)
| _ -> Error (Printf.sprintf "Print on undefined register (%s)" (print_reg r))
end
| Rlabel n -> OK (None, st)
and exec_rtl_instr_at oc rp rtlfunname ({ rtlfunbody; } as f: rtl_fun) st i =
match Hashtbl.find_option rtlfunbody i with
| Some l -> exec_rtl_instrs oc rp rtlfunname f st l
| None -> Error (Printf.sprintf "Jump to undefined label (%s_%d)" rtlfunname i)
and exec_rtl_instrs oc rp rtlfunname f st l =
List.fold_left (fun acc i ->
match acc with
| Error _ -> acc
| OK (Some v, st) -> OK (Some v, st)
| OK (None, st) ->
exec_rtl_instr oc rp rtlfunname f st i
) (OK (None, st)) l
and exec_rtl_fun oc rp st rtlfunname f params =
let regs' = Hashtbl.create 17 in
match List.iter2 (fun n v -> Hashtbl.replace regs' n v) f.rtlfunargs params with
| exception Invalid_argument _ ->
Error (Format.sprintf "RTL: Called function %s with %d arguments, expected %d\n"
rtlfunname
(List.length params)
(List.length f.rtlfunargs)
)
| _ ->
match Hashtbl.find_option f.rtlfunbody f.rtlfunentry with
| None ->
Error (Printf.sprintf "Unknown node (%s_%d)" rtlfunname f.rtlfunentry)
| Some l ->
let regs_save = Hashtbl.copy st.regs in
let st' = {st with regs = regs'; } in
exec_rtl_instrs oc rp rtlfunname f st' l >>= fun (v, st) ->
OK(v, {st with regs = regs_save })
and exec_rtl_prog oc rp memsize params =
let st = init_state memsize in
find_function rp "main" >>= fun f ->
let n = List.length f.rtlfunargs in
let params = take n params in
exec_rtl_fun oc rp st "main" f params >>= fun (v, st) ->
OK v