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

Clean Up Code and Fix Random Things #45

Merged
merged 15 commits into from
May 16, 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
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
Loading