Skip to content

Commit

Permalink
Add more e2e tests, support calling in ir sim
Browse files Browse the repository at this point in the history
  • Loading branch information
ethanuppal committed May 11, 2024
1 parent cba9cd5 commit 1d2b474
Show file tree
Hide file tree
Showing 15 changed files with 94 additions and 44 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
![CI Status](https://github.com/ethanuppal/cs3110_compiler/actions/workflows/ci.yaml/badge.svg)

> "x86 is simple trust me bro"
> Last updated: 2024-05-11 02:29:04.778170
> Last updated: 2024-05-11 02:54:25.925782
```
$ ./main -h
Expand Down
10 changes: 9 additions & 1 deletion lib/frontend/parse_lex.ml
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,21 @@ let lex_and_parse ?(filename = "<stdin>") input =
(fun stmt ->
match stmt with
| Ast.Function { name; params; return; body } ->
let last_stmt_is_return =
if List.is_empty body then false
else
match List.rev body |> List.hd with
| Ast.Return _ -> true
| _ -> false
in
Ast.Function
{
name;
params;
return;
body =
(if return = Type.unit_prim_type then body @ [ Return None ]
(if return = Type.unit_prim_type && not last_stmt_is_return then
body @ [ Return None ]
else body);
}
| other -> other)
Expand Down
87 changes: 55 additions & 32 deletions lib/ir/ir_sim.ml
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
type t = {
context : int Context.t;
mutable current : Cfg.t option;
mutable output : string;
}

let make () = { context = Context.make (); output = "" }
let make () = { context = Context.make (); current = None; output = "" }

let run simulator cfg =
let find_cfg_by_name cfgs name =
List.find (fun cfg -> Cfg.name_of cfg = name) cfgs

let rec run_cfg simulator cfgs cfg =
Context.push simulator.context;
let entry = Cfg.entry_to cfg in
let eval = function
Expand All @@ -14,40 +18,59 @@ let run simulator cfg =
| Operand.Constant int -> int
in
let rec run_aux bb =
Basic_block.to_list bb
|> List.iter (fun ir ->
match ir with
| Ir.Assign (var, oper) ->
Context.insert simulator.context (Variable.to_string var)
(eval oper)
| Ir.Add (var, oper1, oper2) ->
Context.insert simulator.context (Variable.to_string var)
(eval oper1 + eval oper2)
| Ir.Sub (var, oper1, oper2) ->
Context.insert simulator.context (Variable.to_string var)
(eval oper1 - eval oper2)
| Ir.TestEqual (var, oper1, oper2) ->
Context.insert simulator.context (Variable.to_string var)
(if eval oper1 = eval oper2 then 1 else 0)
| Ir.Ref _ | Ir.Deref _ ->
failwith "Ir_sim does not support pointers"
| Ir.DebugPrint oper ->
simulator.output <-
simulator.output ^ Printf.sprintf "%d\n" (eval oper)
| Ir.Call _ | Ir.Return _ ->
failwith "Ir_sim does not support function calls yet");
let cond =
match Basic_block.condition_of bb with
| Always -> true
| Never -> false
| Conditional oper -> eval oper <> 0
let should_exit =
Basic_block.to_list bb
|> List.fold_left
(fun acc ir ->
acc
||
match ir with
| Ir.Assign (var, oper) ->
Context.insert simulator.context (Variable.to_string var)
(eval oper);
false
| Ir.Add (var, oper1, oper2) ->
Context.insert simulator.context (Variable.to_string var)
(eval oper1 + eval oper2);
false
| Ir.Sub (var, oper1, oper2) ->
Context.insert simulator.context (Variable.to_string var)
(eval oper1 - eval oper2);
false
| Ir.TestEqual (var, oper1, oper2) ->
Context.insert simulator.context (Variable.to_string var)
(if eval oper1 = eval oper2 then 1 else 0);
false
| Ir.Ref _ | Ir.Deref _ ->
failwith "Ir_sim does not support pointers"
| Ir.DebugPrint oper ->
simulator.output <-
simulator.output ^ Printf.sprintf "%d\n" (eval oper);
false
| Ir.Call (_, name, _) ->
let called_cfg = find_cfg_by_name cfgs name in
run_cfg simulator cfgs called_cfg;
false
| Ir.Return _ -> true)
false
in
match Cfg.take_branch cfg bb cond with
| Some bb2 -> run_aux bb2
| None -> ()
if not should_exit then
let cond =
match Basic_block.condition_of bb with
| Always -> true
| Never -> false
| Conditional oper -> eval oper <> 0
in
match Cfg.take_branch cfg bb cond with
| Some bb2 -> run_aux bb2
| None -> ()
in
run_aux entry;
Context.pop simulator.context

let run simulator cfgs =
let main_cfg = find_cfg_by_name cfgs "main" in
run_cfg simulator cfgs main_cfg

let output_of simulator = simulator.output
let clear_output simulator = simulator.output <- ""
4 changes: 2 additions & 2 deletions lib/ir/ir_sim.mli
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ type t
(** [make ()] is a new IR simulator. *)
val make : unit -> t

(** [run simulator cfg] simulates [cfg] using [simulator]. *)
val run : t -> Cfg.t -> unit
(** [run simulator cfgs] simulates [cfgs] using [simulator]. *)
val run : t -> Cfg.t list -> unit

(** [dump simulator] is the current standard output of [simulator] as a
human-readable string. *)
Expand Down
7 changes: 7 additions & 0 deletions test/e2e/calling.x86istmb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
func peace_love() {
print 3110
}

func main() {
peace_love()
}
1 change: 1 addition & 0 deletions test/snapshots/type/return4.out
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
func main() -> Unit {
if true {
}
return
}
1 change: 1 addition & 0 deletions test/snapshots/type/type0.in
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
func main() {
print true
return
}
1 change: 1 addition & 0 deletions test/snapshots/type/type0.out
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
func main() -> Unit {
print true
return
}
1 change: 1 addition & 0 deletions test/snapshots/type/type1.out
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ func main() -> Unit {
let x: Int = 1
let y: Int = 2
let z: Int = (x + y)
return
}
3 changes: 3 additions & 0 deletions test/snapshots/type/type12.out
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
func foo(a: Int) -> Unit {
print a
return
}
func bar(a: Int, b: Bool) -> Unit {
print a
print b
return
}
func baz(a: Bool, b: Int, c: Int*) -> Unit {
print a
print b
print c
return
}
2 changes: 2 additions & 0 deletions test/snapshots/type/type5.out
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
func bar() -> Unit {
let x: Bool = true
return
}
func foo() -> Unit {
let x: Int = 4
print (+x)
return
}
2 changes: 2 additions & 0 deletions test/snapshots/type/type6.out
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
func foo() -> Unit {
let x: Int = 1
return
}
func main() -> Unit {
let x: Int = 1
print x
return
}
1 change: 1 addition & 0 deletions test/snapshots/type/type8.out
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
func main() -> Unit {
let x: Bool = (1 == 2)
return
}
8 changes: 4 additions & 4 deletions test/test_passes.ml
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ let make_opts_test passes =
in
let statements = Parse_lex.lex_and_parse ir0_source in
Analysis.infer statements;
let ir = Ir_gen.generate statements in
let main_cfg = List.hd ir in
let cfgs = Ir_gen.generate statements in
let main_cfg = List.hd cfgs in
let liveliness_analysis = Liveliness.analysis_of main_cfg in
let simulator = Ir_sim.make () in
Ir_sim.run simulator main_cfg;
Ir_sim.run simulator [ main_cfg ];
let unopt_output = Ir_sim.output_of simulator in
Passes.apply passes main_cfg liveliness_analysis;
Ir_sim.clear_output simulator;
Ir_sim.run simulator main_cfg;
Ir_sim.run simulator [ main_cfg ];
let opt_output = Ir_sim.output_of simulator in
(check string) "optimization should not change program behavior" unopt_output
opt_output
Expand Down
8 changes: 4 additions & 4 deletions test/test_snapshots.ml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ let type_suite =
the source code [input]. *)
let ir_transform filename input =
let open X86ISTMB in
let open Util in
let statements = Parse_lex.lex_and_parse ~filename input in
Analysis.infer statements;
let ir = Ir_gen.generate statements in
let main_cfg = List.hd ir in
ignore (Liveliness.analysis_of main_cfg);
let cfgs = Ir_gen.generate statements in
List.iter (Liveliness.analysis_of >> ignore) cfgs;
let simulator = Ir_sim.make () in
Ir_sim.run simulator main_cfg;
Ir_sim.run simulator cfgs;
Ir_sim.output_of simulator

let ir_suite =
Expand Down

0 comments on commit 1d2b474

Please sign in to comment.