Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update main to be emission #27

Merged
merged 6 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ test: build

.PHONY: quick_test
quick_test: build
opam exec -- dune exec ./test/test_x86ISTMB.exe -- -q
opam exec -- dune exec ./test/test_x86ISTMB.exe -- --quick-tests

.PHONY: utop
utop: README
Expand Down Expand Up @@ -70,4 +70,4 @@ serve: docs
.PHONY: cloc
cloc:
@make build > /dev/null
@echo "$$(cloc bin lib --json | jq .SUM.code) lines of code"
@echo "$$(cloc --by-file --include-lang=OCaml bin lib test --json | jq .SUM.code) lines of code"
3 changes: 2 additions & 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-06 01:39:50.818851
> Last updated: 2024-05-07 11:28:52.101596

```
$ ./main -h
Expand All @@ -20,6 +20,7 @@ Usage: ./main [-h|-v]
-v,--version prints version info
-g,--gen only produces IR
-O,--optimize runs optimizations
-c,--compile only produces object files
```
```
$ ./main -v
Expand Down
61 changes: 1 addition & 60 deletions bin/main.ml
Original file line number Diff line number Diff line change
@@ -1,62 +1,3 @@
open X86ISTMB

let print_error = Printf.eprintf "error: %s"

let print_help prog =
let open Printf in
printf "%s\n" Meta.get.description;
printf "\n";
printf "Usage: %s [-h|-v]\n" prog;
printf " or: %s FILE [-g][-O]\n" prog;
printf "\n";
printf "-h,--help prints this info\n";
printf "-v,--version prints version info\n";
printf "-g,--gen only produces IR\n";
printf "-O,--optimize runs optimizations\n";
ignore ()

let print_version () =
let open Printf in
printf "%s %s\n" Meta.get.name (Meta.Version.to_string Meta.get.version);
printf "\n";
printf "Written by: %s\n" (String.concat ", " Meta.get.authors)

let show_ir statements =
Analysis.infer statements;
let ir = Ir_gen.generate statements in
let main_cfg = List.hd ir in
let blocks = Cfg.blocks_of main_cfg in
List.iter
(fun b ->
let lst = Basic_block.to_list b in
Printf.printf "Block %i:\n" (Basic_block.id_of b |> Id.int_of);
List.iter (fun bir -> print_endline (Ir.to_string bir)) lst;
print_newline ())
blocks;
let edges = Cfg.edges_of main_cfg in
List.iter
(fun (b1, e, b2) ->
Printf.printf "Block %i" (Basic_block.id_of b1 |> Id.int_of);
Printf.printf " --%s (%s)--> "
(Basic_block.condition_of b1 |> Branch_condition.to_string)
(if e then "t" else "f");
Printf.printf "Block %i" (Basic_block.id_of b2 |> Id.int_of);
print_newline ())
edges

let file_driver path flags =
let source = Util.read_file path in
try
let statements = Parse_lex.lex_and_parse source in
ignore statements;
if List.mem Cli.OnlyIR flags then show_ir statements
else failwith "compiler not done yet"
with Parse_lex.ParseError msg -> print_error (msg ^ "\n")

let () =
match Sys.argv |> Cli.parse with
| Help { prog } -> print_help prog
| Version { prog = _ } -> print_version ()
| File { prog = _; path; flags } -> file_driver path flags
| Error { prog; msg } ->
Printf.sprintf "%s\nuse %s -h\n" msg prog |> print_error
let () = Driver.main Sys.argv
6 changes: 5 additions & 1 deletion lib/backend/asm.ml
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,11 @@ end = struct
("section ." ^ section.name)
:: (display_indent ^ "align " ^ string_of_int section.align)
:: (BatDynArray.to_list section.contents
|> List.map (Instruction.to_nasm >> ( ^ ) display_indent))
|> List.map (fun instr ->
let str = Instruction.to_nasm instr in
match instr with
| Label _ -> str
| _ -> display_indent ^ str))
|> String.concat "\n"
end

Expand Down
96 changes: 51 additions & 45 deletions lib/backend/liveliness.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ open Util
open Ir

(** A set of IR variables. *)
module VariableSet = Set.Make (Variable)
module VariableSet = struct
include Set.Make (Variable)

let to_string set =
"{"
^ (to_list set |> List.map Variable.to_string |> String.concat ", ")
^ "}"
end

(** Liveliness analysis of an IR operation. *)
type instr_analysis = {
Expand Down Expand Up @@ -59,22 +66,14 @@ module BasicBlockAnalysis = struct

let to_string analysis =
let analysis = rep_ok analysis in
let set_to_string set =
let elements_string =
VariableSet.elements set
|> List.map Variable.to_string
|> String.concat ", "
in
"{" ^ elements_string ^ "}"
in
"BasicBlockAnalysis {"
^ (Seq.init (Array.length analysis) id
|> List.of_seq
|> List.map (fun i ->
"\n ir[" ^ string_of_int i ^ "] <=> {live_in = "
^ set_to_string (live_before_instr analysis i)
^ VariableSet.to_string (live_before_instr analysis i)
^ ", live_out = "
^ set_to_string (live_after_instr analysis i)
^ VariableSet.to_string (live_after_instr analysis i)
^ "}")
|> String.concat "")
^ "\n}"
Expand All @@ -84,45 +83,51 @@ end
liveliness rules for instruction [ir] at index [ir_index] in basic block
[bb], where [bb] is in [cfg] and has associated liveliness analysis
[analysis = IdMap.find liveliness (Basic_block.id_of bb)], and where
[is_final] if and only if [ir] is the final instruction in [bb], and returns
whether any updates were made to liveliness information. *)
[is_final] if and only if [ir] is the final instruction in [bb], updating
partial results in [liveliness] and returning whether any updates were made
to liveliness information. *)
let apply_rules liveliness analysis cfg bb ir ir_idx ~is_final =
let result = ref false in
let instr_analysis = analysis.(ir_idx) in
let update_live_out new_live_out =
let old_live_out = instr_analysis.live_out in
instr_analysis.live_out <- new_live_out;
if old_live_out <> new_live_out then result := true
let old_live_in = instr_analysis.live_in in
let old_live_out = instr_analysis.live_out in
let check_for_changes () =
if
VariableSet.cardinal old_live_in
> VariableSet.cardinal instr_analysis.live_in
then failwith "??";
(match (old_live_out, instr_analysis.live_out) with
| Some old_live_out, Some new_live_out ->
not (VariableSet.equal old_live_out new_live_out)
| None, None -> false
| _ -> true)
|| not (VariableSet.equal old_live_in instr_analysis.live_in)
in
let update_live_in new_live_in =
let old_live_in = instr_analysis.live_in in
instr_analysis.live_in <- new_live_in;
if old_live_in <> new_live_in then result := true
let bring_incoming () =
(if is_final then
let live_out_of_succ =
Cfg.out_edges cfg bb
|> List.fold_left
(fun acc (bb_succ, _) ->
let incoming_live_partial =
IdMap.find liveliness (Basic_block.id_of bb_succ)
|> BasicBlockAnalysis.live_in
in
VariableSet.union acc incoming_live_partial)
VariableSet.empty
in
instr_analysis.live_out <- Some live_out_of_succ);
instr_analysis.live_in <-
VariableSet.union instr_analysis.live_in
(BasicBlockAnalysis.live_after_instr analysis ir_idx)
in
let read_var var =
update_live_in (VariableSet.add var instr_analysis.live_in)
instr_analysis.live_in <- VariableSet.add var instr_analysis.live_in
in
let read_op op = Operand.var_of_opt op |> Option.map read_var |> ignore in
let read_op = Operand.var_of_opt >> Option.map read_var >> ignore in
let write_var var =
let incoming_live =
VariableSet.remove var
(BasicBlockAnalysis.live_after_instr analysis ir_idx)
in
update_live_in (VariableSet.union instr_analysis.live_in incoming_live)
instr_analysis.live_in <- VariableSet.remove var instr_analysis.live_in
in
(if is_final then
let live_out_of_succ =
Cfg.out_edges cfg bb
|> List.fold_left
(fun acc (bb_succ, _) ->
let incoming_live_partial =
IdMap.find liveliness (Basic_block.id_of bb_succ)
|> BasicBlockAnalysis.live_in
in
VariableSet.union acc incoming_live_partial)
VariableSet.empty
in
update_live_out (Some live_out_of_succ));
bring_incoming ();
(match ir with
| DebugPrint op -> read_op op
| Assign (var, op) | Deref (var, op) | Ref (var, op) ->
Expand All @@ -132,10 +137,11 @@ let apply_rules liveliness analysis cfg bb ir ir_idx ~is_final =
write_var var;
read_op op1;
read_op op2);
!result
check_for_changes ()

(** [pass work_list liveliness cfg bb] performs a single pass of liveliness
analysis on a basic block *)
analysis on a basic block, updating partial results in [liveliness] and
returning whether any updates were made to liveliness information. *)
let pass work_list liveliness cfg bb =
let result = ref false in
let analysis = IdMap.find liveliness (Basic_block.id_of bb) in
Expand All @@ -153,7 +159,7 @@ let pass work_list liveliness cfg bb =
!result

(** [iterate liveliness cfg] performs an iteration of liveliness analysis on
[cfg], updating partial results in [liveliness], and returning whether any
[cfg], updating partial results in [liveliness] and returning whether any
changes were made. *)
let iterate liveliness cfg =
let work_list = Queue.create () in
Expand Down
2 changes: 2 additions & 0 deletions lib/backend/liveliness.mli
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ open Util
(** A value of type [VariableSet.t] is a set of IR variables. *)
module VariableSet : sig
include Set.S with type elt = Variable.t

val to_string : t -> string
end

(** Liveliness analysis of a basic block. *)
Expand Down
39 changes: 0 additions & 39 deletions lib/cli.ml

This file was deleted.

File renamed without changes.
File renamed without changes.
3 changes: 3 additions & 0 deletions lib/ir/basic_block.ml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ let length_of bb = BatDynArray.length bb.contents
let condition_of bb = bb.condition
let set_condition bb cond = bb.condition <- cond
let add_ir basic_block ir = BatDynArray.add basic_block.contents ir
let get_ir basic_block index = BatDynArray.get basic_block.contents index
let set_ir basic_block index ir = BatDynArray.set basic_block.contents index ir
let rem_ir basic_block index = BatDynArray.remove_at index basic_block.contents
let to_list basic_block = BatDynArray.to_list basic_block.contents
let equal bb1 bb2 = bb1.id = bb2.id
let hash bb = Id.int_of bb.id |> Int.hash
Expand Down
17 changes: 17 additions & 0 deletions lib/ir/basic_block.mli
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,23 @@ val set_condition : t -> Branch_condition.t -> unit
(** [add_ir basic_block ir] adds [ir] to the end of [basic_block]. *)
val add_ir : t -> Ir.t -> unit

(** [get_ir bb idx] is the IR instruction at index [idx] in [bb].

Requires: [Basic_block.length_of bb > idx]. *)
val get_ir : t -> int -> Ir.t

(** [set_ir bb idx ir] replaces the IR instruction at index [idx] in [bb] with
[ir].

Requires: [Basic_block.length_of bb > idx]. *)
val set_ir : t -> int -> Ir.t -> unit

(** [rem_ir bb idx] removes the IR instruction at index [idx] in [bb], shifting
all the subsequent indices/IR instructions backward.

Requires: [Basic_block.length_of bb > idx]. *)
val rem_ir : t -> int -> unit

(** [to_list basic_block] are the IR operations in [basic_block] in order as a
list. *)
val to_list : t -> Ir.t list
Expand Down
11 changes: 11 additions & 0 deletions lib/ir/ir.ml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@ type t =
| DebugPrint of Operand.t
(* | Call of string * Operand.t list *)

(** [kill_of ir] is [Some var] if [var] is assigned to in [ir] and [None]
otherwise. *)
let kill_of = function
| Assign (var, _)
| Add (var, _, _)
| Sub (var, _, _)
| Ref (var, _)
| Deref (var, _)
| TestEqual (var, _, _) -> Some var
| DebugPrint _ -> None

let to_string =
let open Printf in
function
Expand Down
4 changes: 3 additions & 1 deletion lib/ir/ir_sim.ml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ let run simulator cfg =
| Some bb2 -> run_aux bb2
| None -> ()
in
run_aux entry
run_aux entry;
Context.pop simulator.context

let output_of simulator = simulator.output
let clear_output simulator = simulator.output <- ""
2 changes: 2 additions & 0 deletions lib/ir/ir_sim.mli
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ val run : t -> Cfg.t -> unit
(** [dump simulator] is the current standard output of [simulator] as a
human-readable string. *)
val output_of : t -> string

val clear_output : t -> unit
24 changes: 24 additions & 0 deletions lib/ir/pass.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
type t =
| Basic of (Basic_block.t * Liveliness.BasicBlockAnalysis.t -> unit)
| Combine of t list
| Repeat of t * int

let make f = Basic f
let compose pass1 pass2 = Combine [ pass1; pass2 ]
let combine passes = Combine passes
let repeat n pass = Repeat (pass, n)

let execute pass bb liveliness =
let rec execute_aux bb = function
| Basic f -> f (bb, liveliness)
| Combine passes -> List.iter (execute_aux bb) passes
| Repeat (pass, n) ->
for _ = 0 to n - 1 do
execute_aux bb pass
done
in
execute_aux bb pass

module type PASS = sig
val pass : t
end
Loading