Skip to content

Commit

Permalink
Clean Up Code and Fix Random Things (#45)
Browse files Browse the repository at this point in the history
* Separate namespace and parameter tests

* Semi-working

* The easy solution to the register allocation issue

* More parameter spilling tests

* Remove basic test suite

* Moved some CLI code to bin

* Made -g work

* Put asm cleaning under optimizations

* An improvement on dead code elimination

* Remove dead code elimination because fixing will take too long

* Rename files to camel case in lib

* Rename opt_tests

* Update install instructions
  • Loading branch information
Yey007 authored May 16, 2024
1 parent 78b77d9 commit 0d86cd6
Show file tree
Hide file tree
Showing 46 changed files with 241 additions and 317 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ gitlog.txt
docs/html/*
!docs/html/.gitkeep
build_dir/
bin/*
!bin/.gitkeep
demo/*
22 changes: 15 additions & 7 deletions INSTALL.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
# Installation Instructions

> [!NOTE]
> This document is not a user manual.
> It simply explains how to get the project onto your computer.
> To see how to get it up and running, read the [user manual](docs/user_manual.md).
> This document is not a user manual.
> It simply explains how to get the project onto your computer and running.
> To see how to use the compiler, check out the [user manual](docs/user_manual.md).
These instructions assume you already have OCaml installed.
## Install System Dependencies
These instructions assume you already have OCaml and `make` installed.

You'll need `nasm` for compiling assembly and `clang` for compiling and linking the runtime. The recommended way to install these on Linux and Max is through [Homebrew](https://brew.sh/).

Once you have Homebrew, run `brew install llvm nasm`. If you don't want to use Homebrew,
you're welcome to install the dependencies on your own, but they must be in `PATH`.

## Build and Run
1. Create a new `opam` switch by running `opam switch create cs3110-compiler ocaml-base-compiler.5.1.1`
2. Install the required libraries: `opam install menhir batteries ounit2`
3. Build the project by running `dune build`
4. Use `dune exec bin/main.exe -- -h` to see usage instructions. Replace `-h` in the previous command with the flags you want to use.
2. Install the required libraries: `make deps`
3. Build the project by running `make`. A main executable will be copied into your directory.
4. Use `./main -h` to see usage instructions. Replace `-h` in the previous command with the flags you want to use.
3 changes: 1 addition & 2 deletions 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-16 13:25:30.792439
> Last updated: 2024-05-16 13:46:39.281139
```
$ ./main -h
Expand All @@ -20,7 +20,6 @@ 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
12 changes: 4 additions & 8 deletions lib/user/cli.ml → bin/cli.ml
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
type flag =
| OnlyIR
| OnlyObject
| Optimize
open X86ISTMB

type action =
| Error of { msg : string }
| Help
| Version
| Compile of {
paths : string list;
flags : flag list;
flags : Driver.flag list;
}

type parse_result = {
Expand All @@ -27,9 +24,8 @@ let parse args =
List.iter
(fun s ->
match s with
| "-g" | "--gen" -> flags := OnlyIR :: !flags
| "-O" | "--optimize" -> flags := Optimize :: !flags
| "-c" | "--compile" -> flags := OnlyObject :: !flags
| "-g" | "--gen" -> flags := Driver.OnlyIR :: !flags
| "-O" | "--optimize" -> flags := Driver.Optimize :: !flags
| _ -> paths := s :: !paths)
args;
Compile { paths = !paths; flags = !flags }
Expand Down
8 changes: 2 additions & 6 deletions lib/user/cli.mli → bin/cli.mli
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
(** Compiler flags *)
type flag =
| OnlyIR
| OnlyObject
| Optimize
open X86ISTMB

(** The various actions the program can take. *)
type action =
Expand All @@ -11,7 +7,7 @@ type action =
| Version
| Compile of {
paths : string list;
flags : flag list;
flags : Driver.flag list;
}

(** The result of parsing CLI arguments. [prog] is the name/path of the running
Expand Down
39 changes: 38 additions & 1 deletion bin/main.ml
Original file line number Diff line number Diff line change
@@ -1,3 +1,40 @@
open X86ISTMB

let () = Driver.main Sys.argv
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 rec dispatch action prog =
match action with
| Cli.Help -> print_help prog
| Version -> print_version ()
| Compile { paths; flags } -> (
if List.is_empty paths then
dispatch (Error { msg = "expected at least one file name" }) prog
else
try Driver.compile paths flags None
with exn -> print_error (Printexc.to_string exn))
| Error { msg } -> Printf.sprintf "%s\nuse %s -h\n" msg prog |> print_error

let main args =
let parse = Cli.parse args in
dispatch parse.action parse.prog

let () = main Sys.argv
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
14 changes: 7 additions & 7 deletions lib/backend/asm_emit.ml → lib/backend/asmEmit.ml
Original file line number Diff line number Diff line change
Expand Up @@ -242,14 +242,14 @@ let emit_bb text_section data_section cfg regalloc param_ctx bb =
Asm.Section.add text_section
(Label
(Asm.Label.make ~is_global:false ~is_external:false
(Basic_block.label_for bb)));
bb |> Basic_block.to_list
(BasicBlock.label_for bb)));
bb |> BasicBlock.to_list
|> List.iter (emit_ir text_section data_section regalloc param_ctx);
match Basic_block.condition_of bb with
match BasicBlock.condition_of bb with
| Never | Conditional (Constant 0) -> ()
| Always | Conditional (Constant _) ->
let dest_bb = Cfg.take_branch cfg bb true |> Option.get in
Asm.Section.add text_section (Jmp (Label (Basic_block.label_for dest_bb)))
Asm.Section.add text_section (Jmp (Label (BasicBlock.label_for dest_bb)))
| Conditional op -> (
let true_bb = Cfg.take_branch cfg bb true |> Option.get in
let false_bb = Cfg.take_branch cfg bb false |> Option.get in
Expand All @@ -258,9 +258,9 @@ let emit_bb text_section data_section cfg regalloc param_ctx bb =
Asm.Section.add text_section
(Cmp (emit_var regalloc var, Intermediate 0));
Asm.Section.add text_section
(Je (Label (Basic_block.label_for true_bb)));
(Je (Label (BasicBlock.label_for true_bb)));
Asm.Section.add text_section
(Jmp (Label (Basic_block.label_for false_bb)))
(Jmp (Label (BasicBlock.label_for false_bb)))
| Constant _ | StringLiteral _ -> failwith "failure")

let emit_preamble ~text_section ~data_section:_ ffi_names decl_names =
Expand Down Expand Up @@ -315,7 +315,7 @@ let emit_cfg ~text_section ~data_section cfg regalloc =

(* now that we've set up the stack and saved callee-save registers, we can
jump to the entrypoint. *)
Asm.Section.add text_section (Jmp (Label (Basic_block.label_for entry)));
Asm.Section.add text_section (Jmp (Label (BasicBlock.label_for entry)));

(* we'll need a parameter passing context so that the GetParam IR can work *)
let param_ctx = ParameterPassingContext.make () in
Expand Down
File renamed without changes.
14 changes: 7 additions & 7 deletions lib/backend/liveliness.ml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ module BasicBlockAnalysis = struct
analysis

let make bb =
Array.init (Basic_block.length_of bb) (fun _ ->
Array.init (BasicBlock.length_of bb) (fun _ ->
{ live_in = VariableSet.empty; live_out = None })
|> rep_ok

Expand Down Expand Up @@ -81,7 +81,7 @@ end
(** [apply_rules liveliness analysis cfg bb ir ir_index ~is_final] applies
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
[analysis = IdMap.find liveliness (BasicBlock.id_of bb)], and where
[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. *)
Expand All @@ -108,7 +108,7 @@ let apply_rules liveliness analysis cfg bb ir ir_idx ~is_final =
|> List.fold_left
(fun acc (bb_succ, _) ->
let incoming_live_partial =
IdMap.find liveliness (Basic_block.id_of bb_succ)
IdMap.find liveliness (BasicBlock.id_of bb_succ)
|> BasicBlockAnalysis.live_in
in
VariableSet.union acc incoming_live_partial)
Expand Down Expand Up @@ -136,12 +136,12 @@ let apply_rules liveliness analysis cfg bb ir ir_idx ~is_final =
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
let ir_count = Basic_block.length_of bb in
let analysis = IdMap.find liveliness (BasicBlock.id_of bb) in
let ir_count = BasicBlock.length_of bb in
for rev_i = 1 to ir_count do
let i = ir_count - rev_i in
result :=
apply_rules liveliness analysis cfg bb (Basic_block.get_ir bb i) i
apply_rules liveliness analysis cfg bb (BasicBlock.get_ir bb i) i
~is_final:(rev_i = 1)
|| !result
done;
Expand All @@ -166,7 +166,7 @@ let analysis_of cfg =
let liveliness = IdMap.create 16 in
Cfg.iter
(fun bb ->
IdMap.add liveliness (Basic_block.id_of bb) (BasicBlockAnalysis.make bb))
IdMap.add liveliness (BasicBlock.id_of bb) (BasicBlockAnalysis.make bb))
cfg;
let rec converge () = if iterate liveliness cfg then converge () in
converge ();
Expand Down
6 changes: 3 additions & 3 deletions lib/backend/liveliness.mli
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ module BasicBlockAnalysis : sig
(** [make bb] is an empty liveliness analysis for the basic block [bb]. It is
guaranteed to never mutate or copy [bb] internally.
Requires: [Basic_block.length_of bb > 0]. *)
val make : Basic_block.t -> t
Requires: [BasicBlock.length_of bb > 0]. *)
val make : BasicBlock.t -> t

(** [live_in analysis] is the set of variables live at the start of the the
analyzed basic block.
Expand Down Expand Up @@ -47,7 +47,7 @@ end
(** [analysis_of cfg] is an association between the basic blocks in [cfg] and
their liveliness analyses. In particular, let [a] be the result of this
function and let [bb] be a basic block in [cfg] Then,
[Util.IdMap.find a (Basic_block.id_of bb)] is the liveliness analysis of
[Util.IdMap.find a (BasicBlock.id_of bb)] is the liveliness analysis of
[bb].
Requires: every basic block in [cfg] has at least one IR instruction. *)
Expand Down
2 changes: 1 addition & 1 deletion lib/backend/regalloc/instrOrdering.ml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ let make cfg =
let n = ref 0 in
Cfg.iter
(fun bb ->
OrderMap.add map (Basic_block.id_of bb) !n;
OrderMap.add map (BasicBlock.id_of bb) !n;
n := !n + 1)
cfg;
map
Expand Down
6 changes: 3 additions & 3 deletions lib/backend/regalloc/regalloc.ml
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ let live_intervals (cfg : Cfg.t) (liveliness : BBAnalysis.t IdMap.t)

Cfg.iter
(fun bb ->
let bb_id = Basic_block.id_of bb in
let bb_id = BasicBlock.id_of bb in
let analysis = IdMap.find liveliness bb_id in
for instr_idx = 0 to Basic_block.length_of bb - 1 do
for instr_idx = 0 to BasicBlock.length_of bb - 1 do
let live_set = BBAnalysis.live_before_instr analysis instr_idx in
let kill_var = Basic_block.get_ir bb instr_idx |> Ir.kill_of in
let kill_var = BasicBlock.get_ir bb instr_idx |> Ir.kill_of in
let used_set =
match kill_var with
| Some var -> Liveliness.VariableSet.add var live_set
Expand Down
18 changes: 9 additions & 9 deletions lib/frontend/ir_gen.ml → lib/frontend/irGen.ml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ let rec generate_expr ctx cfg block expr =
| Equals -> Ir.TestEqual (result, lhs_result, rhs_result)
| _ -> failwith "not implemented"
in
Basic_block.add_ir block ir_instr;
BasicBlock.add_ir block ir_instr;
Operand.make_var result
| Prefix { op; rhs; _ } ->
let result = Variable.make () in
Expand All @@ -44,12 +44,12 @@ let rec generate_expr ctx cfg block expr =
| BitAnd -> Ir.Ref (result, rhs_result)
| _ -> failwith "not implemented"
in
Basic_block.add_ir block ir_instr;
BasicBlock.add_ir block ir_instr;
Operand.make_var result
| Call { name; args; _ } ->
let call_result = Variable.make () in
let arg_results = List.map (generate_expr ctx cfg block) args in
Basic_block.add_ir block (Ir.Call (call_result, name, arg_results));
BasicBlock.add_ir block (Ir.Call (call_result, name, arg_results));
Operand.make_var call_result

(** [generate_stmt ctx cfg block stmt] adds IR for [stmt] (and potentially more
Expand All @@ -61,7 +61,7 @@ let rec generate_stmt ctx cfg block = function
let result = generate_expr ctx cfg block expr in
let result_var = Variable.make () in
let assign = Ir.Assign (result_var, result) in
Basic_block.add_ir block assign;
BasicBlock.add_ir block assign;
Context.insert ctx name result_var;
block
| Assignment (name, expr) ->
Expand All @@ -70,7 +70,7 @@ let rec generate_stmt ctx cfg block = function
Context.get ctx name |> get_or_else (UnboundVariable { name })
in
let assign = Ir.Assign (result_var, result) in
Basic_block.add_ir block assign;
BasicBlock.add_ir block assign;
block
| If { cond; body } ->
let cond_result = generate_expr ctx cfg block cond in
Expand All @@ -90,7 +90,7 @@ let rec generate_stmt ctx cfg block = function
failwith "not allowed"
| Print expr ->
let to_print = generate_expr ctx cfg block expr in
Basic_block.add_ir block (Ir.DebugPrint to_print);
BasicBlock.add_ir block (Ir.DebugPrint to_print);
block
| ExprStatement expr ->
ignore (generate_expr ctx cfg block expr);
Expand All @@ -99,8 +99,8 @@ let rec generate_stmt ctx cfg block = function
(match expr_opt with
| Some expr ->
let to_return = generate_expr ctx cfg block expr in
Basic_block.add_ir block (Ir.Return (Some to_return))
| None -> Basic_block.add_ir block (Ir.Return None));
BasicBlock.add_ir block (Ir.Return (Some to_return))
| None -> BasicBlock.add_ir block (Ir.Return None));
block
| Namespace { name; contents } ->
Context.push ctx;
Expand All @@ -127,7 +127,7 @@ let rec generate_top_level ctx ffi_names_ref decl_names_ref stmt =
let param_var = Variable.make () in
Context.insert ctx param param_var;
let entry = Cfg.entry_to cfg in
Basic_block.add_ir entry (Ir.GetParam param_var))
BasicBlock.add_ir entry (Ir.GetParam param_var))
params;
ignore (generate_stmt_lst ctx cfg (Cfg.entry_to cfg) body);
[ cfg ]
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 0 additions & 2 deletions lib/ir/basic_block.ml → lib/ir/basicBlock.ml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
(** TODO: needs tests *)

let bb_gen = Id.Gen.make ()

type t = {
Expand Down
8 changes: 4 additions & 4 deletions lib/ir/basic_block.mli → lib/ir/basicBlock.mli
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,25 @@ 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]. *)
Requires: [BasicBlock.length_of bb > idx]. *)
val get_ir : t -> int -> Ir.t

(** [get_orig_idx bb idx] is the original index of the IR instruction at index
[idx] in [bb]; this original index will never changed.
Requires: [Basic_block.length_of bb > idx]. *)
Requires: [BasicBlock.length_of bb > idx]. *)
val get_orig_idx : t -> int -> int

(** [set_ir bb idx ir] replaces the IR instruction at index [idx] in [bb] with
[ir].
Requires: [Basic_block.length_of bb > idx]. *)
Requires: [BasicBlock.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]. *)
Requires: [BasicBlock.length_of bb > idx]. *)
val rem_ir : t -> int -> unit

(** [to_list bb] are the IR operations in [bb] in order as a list. *)
Expand Down
Loading

0 comments on commit 0d86cd6

Please sign in to comment.