Skip to content

Commit

Permalink
Merge branch 'main' into parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
Yey007 committed May 16, 2024
2 parents e120090 + a1fccdd commit 9b5b97f
Show file tree
Hide file tree
Showing 20 changed files with 187 additions and 39 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ docs/html/*
build_dir/
bin/*
!bin/.gitkeep
demo/*
demo/*
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ build:
@cp _build/install/default/bin/x86ISTMB ./main
@chmod u+x ./main
@chmod u+x .githooks/pre-commit
@make README
@make README 1> /dev/null

.PHONY: protect
protect:
Expand Down
4 changes: 2 additions & 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 00:16:04.014791
> Last updated: 2024-05-16 01:16:02.840605
```
$ ./main -h
Expand Down Expand Up @@ -54,6 +54,6 @@ Written by: Utku Melemeti, Ethan Uppal, Jeffrey Huang
The `Makefile` in the project root directory enables easy usage.
Simply run `make` to build the project executable, `./main`.
`make clean` will clear all build and executable files.
Documentation is in [introduction.md](docs/introduction.md).
Documentation is available online at the [wiki](https://github.com/ethanuppal/cs3110_compiler/wiki).
Installation instructions are in [INSTALL.md](INSTALL.md).
A full user manual is in [user_manual.md](docs/user_manual.md).
2 changes: 1 addition & 1 deletion README.md.template
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,6 @@ $ ./main -v
The `Makefile` in the project root directory enables easy usage.
Simply run `make` to build the project executable, `./main`.
`make clean` will clear all build and executable files.
Documentation is in [introduction.md](docs/introduction.md).
Documentation is available online at the [wiki](https://github.com/ethanuppal/cs3110_compiler/wiki).
Installation instructions are in [INSTALL.md](INSTALL.md).
A full user manual is in [user_manual.md](docs/user_manual.md).
3 changes: 3 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This folder contains information regarding project installation and setup.
Please read the project wiki (link in [main README](../README.md)) for language reference.

11 changes: 9 additions & 2 deletions lib/backend/asm.ml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ module Label = struct
}

let make ~is_global ~is_external name = { is_global; is_external; name }
let name_of label = label.name

let to_nasm label =
match (label.is_global, label.is_external) with
Expand All @@ -92,7 +93,7 @@ module Instruction = struct
| Mov of Operand.t * Operand.t
| Add of Operand.t * Operand.t
| Sub of Operand.t * Operand.t
| IMul of Operand.t
| IMul of Operand.t * Operand.t
| Push of Operand.t
| Pop of Operand.t
| Call of Operand.t
Expand All @@ -111,7 +112,8 @@ module Instruction = struct
"add " ^ Operand.to_nasm op1 ^ ", " ^ Operand.to_nasm op2
| Sub (op1, op2) ->
"sub " ^ Operand.to_nasm op1 ^ ", " ^ Operand.to_nasm op2
| IMul op -> "imul " ^ Operand.to_nasm op
| IMul (op1, op2) ->
"imul " ^ Operand.to_nasm op1 ^ ", " ^ Operand.to_nasm op2
| Push op -> "push " ^ Operand.to_nasm op
| Pop op -> "pop " ^ Operand.to_nasm op
| Call op -> "call " ^ Operand.to_nasm op
Expand Down Expand Up @@ -146,6 +148,11 @@ module Section = struct
| Label _ -> str
| _ -> display_indent ^ str))
|> String.concat "\n"

let get_instr section idx = BatDynArray.get section.contents idx
let set_instr section idx instr = BatDynArray.set section.contents idx instr
let rem_instr section idx = BatDynArray.delete section.contents idx
let length_of section = BatDynArray.length section.contents
end

module AssemblyFile = struct
Expand Down
20 changes: 19 additions & 1 deletion lib/backend/asm.mli
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ module Label : sig
if [is_external], but not both. *)
val make : is_global:bool -> is_external:bool -> string -> t

(** [name_of label] is the name of [label]. *)
val name_of : t -> string

(** [to_nasm label] is the NASM representation of [label]. *)
val to_nasm : t -> string
end
Expand All @@ -75,7 +78,7 @@ module Instruction : sig
| Mov of Operand.t * Operand.t
| Add of Operand.t * Operand.t
| Sub of Operand.t * Operand.t
| IMul of Operand.t
| IMul of Operand.t * Operand.t
| Push of Operand.t
| Pop of Operand.t
| Call of Operand.t
Expand Down Expand Up @@ -109,6 +112,21 @@ module Section : sig

(** [to_nasm section] is the NASM representation of [section]. *)
val to_nasm : t -> string

(** [get_instr section idx] is the instruction at index [idx] in [section]. *)
val get_instr : t -> int -> Instruction.t

(** [set_instr section idx instr] sets the instruction at index [idx] in
[section] to [instr]. *)
val set_instr : t -> int -> Instruction.t -> unit

(** [rem_instr section idx] deletes the instruction at index [idx] in
[section], invalidating all subsequent indices for [get_instr] and
[set_instr]. *)
val rem_instr : t -> int -> unit

(** [length_of section] is the number of instructions in [section]. *)
val length_of : t -> int
end

(** Contains functionality for creating assembly files. *)
Expand Down
51 changes: 51 additions & 0 deletions lib/backend/asm_clean.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
let apply_clean_rules_single section i =
let cur = Asm.Section.get_instr section i in
match cur with
| Asm.Instruction.Mov (o1, o2) when o1 = o2 ->
Asm.Section.rem_instr section i;
true
| _ -> false

let apply_clean_rules_pair section i =
let cur = Asm.Section.get_instr section i in
let next = Asm.Section.get_instr section (i + 1) in
let delete_pair () =
Asm.Section.rem_instr section (i + 1);
Asm.Section.rem_instr section i
in
match (cur, next) with
| Asm.Instruction.Jmp (Asm.Operand.Label label), Asm.Instruction.Label label2
when label = Asm.Label.name_of label2 ->
delete_pair ();
true
| Push op1, Pop op2 when op1 = op2 ->
delete_pair ();
true
| (Add (r1, v1), Sub (r2, v2) | Sub (r1, v1), Add (r2, v2))
when r1 = r2 && v1 = v2 ->
delete_pair ();
true
| _ -> false

let apply_clean_rules section i =
let first_try =
if i > 0 then apply_clean_rules_pair section (i - 1) else false
in
let second_try =
if i < Asm.Section.length_of section then apply_clean_rules_single section i
else false
in
first_try || second_try

let clean_pass section =
let length = Asm.Section.length_of section in
let did_change = ref false in
for rev_i = 0 to length - 1 do
let i = length - rev_i - 1 in
did_change := apply_clean_rules section i || !did_change
done;
!did_change

let clean section =
let rec clean_aux section = if clean_pass section then clean_aux section in
clean_aux section
3 changes: 3 additions & 0 deletions lib/backend/asm_clean.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(** [clean section] minimizes redundant assembly in [section] using naive rules
that are guaranteed to not affect the data. *)
val clean : Asm.Section.t -> unit
40 changes: 28 additions & 12 deletions lib/backend/asm_emit.ml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ let emit_restore_registers text registers =
Asm.Section.add text (Add (Register RSP, Intermediate extra_offset));
Asm.Section.add_all text pop_instructions

let emit_call text regalloc name args =
let emit_call text regalloc name args return_loc_opt =
let open Asm.Instruction in
let module ParamCtx = ParameterPassingContext in
let param_ctx = ParamCtx.make () in
Expand Down Expand Up @@ -109,18 +109,30 @@ let emit_call text regalloc name args =
let spill_size = var_size * max_spill in
let offset = align_offset spill_size in

emit_save_registers text Asm.Register.caller_saved_data_registers;
let save_registers =
List.filter
(fun reg ->
match return_loc_opt with
| Some (Asm.Operand.Register return_reg) -> reg <> return_reg
| _ -> true)
Asm.Register.caller_saved_data_registers
in

emit_save_registers text save_registers;
Asm.Section.add text (Sub (Register RSP, Intermediate offset));
Asm.Section.add_all text spill_pushes;
Asm.Section.add_all text reg_movs;
Asm.Section.add text (Call (Label name));
(match return_loc_opt with
| Some return_loc -> Asm.Section.add text (Mov (return_loc, Register RAX))
| None -> ());
Asm.Section.add text (Add (Register RSP, Intermediate (offset + spill_size)));
emit_restore_registers text Asm.Register.caller_saved_data_registers
emit_restore_registers text save_registers

let emit_get_param text regalloc param_ctx var =
match ParameterPassingContext.get_next param_ctx with
| RegisterParam dest ->
Asm.Section.add text (Mov (emit_var regalloc var, Register dest))
| RegisterParam src ->
Asm.Section.add text (Mov (emit_var regalloc var, Register src))
| SpilledParam i -> (
let rbp_offset = var_size + (var_size * i) in
let src = Asm.Operand.Deref (RBP, rbp_offset) in
Expand All @@ -139,8 +151,7 @@ let emit_get_param text regalloc param_ctx var =

let emit_return text regalloc op_opt =
(match op_opt with
| Some value ->
Asm.Section.add text (Mov (Register RAX, emit_oper regalloc value))
| Some op -> Asm.Section.add text (Mov (Register RAX, emit_oper regalloc op))
| None -> ());

emit_restore_registers text Asm.Register.callee_saved_data_registers;
Expand All @@ -162,12 +173,17 @@ let emit_ir text regalloc param_ctx = function
Mov (emit_var regalloc var, emit_oper regalloc op);
Sub (emit_var regalloc var, emit_oper regalloc op2);
]
| Mul (var, op, op2) ->
Asm.Section.add_all text
[
Mov (emit_var regalloc var, emit_oper regalloc op);
IMul (emit_var regalloc var, emit_oper regalloc op2);
]
| Ref _ -> failwith "ref not impl"
| Deref _ -> failwith "deref not impl"
| DebugPrint op -> emit_call text regalloc debug_print_symbol [ op ]
| DebugPrint op -> emit_call text regalloc debug_print_symbol [ op ] None
| Call (var, name, args) ->
emit_call text regalloc (mangle name) args;
Asm.Section.add text (Mov (emit_var regalloc var, Register RAX))
emit_call text regalloc (mangle name) args (Some (emit_var regalloc var))
| GetParam var -> emit_get_param text regalloc param_ctx var
| Return op_opt -> emit_return text regalloc op_opt

Expand All @@ -188,8 +204,8 @@ let emit_bb text cfg regalloc param_ctx bb =
match op with
| Variable var ->
Asm.Section.add text (Cmp (emit_var regalloc var, Intermediate 0));
Asm.Section.add text (Je (Label (Basic_block.label_for false_bb)));
Asm.Section.add text (Jmp (Label (Basic_block.label_for true_bb)))
Asm.Section.add text (Je (Label (Basic_block.label_for true_bb)));
Asm.Section.add text (Jmp (Label (Basic_block.label_for false_bb)))
| Constant _ -> failwith "failure")

let emit_preamble ~text =
Expand Down
17 changes: 2 additions & 15 deletions lib/backend/liveliness.ml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
open Util
open Ir

(** A set of IR variables. *)
module VariableSet = struct
Expand Down Expand Up @@ -128,20 +127,8 @@ let apply_rules liveliness analysis cfg bb ir ir_idx ~is_final =
instr_analysis.live_in <- VariableSet.remove var instr_analysis.live_in
in
bring_incoming ();
(match ir with
| DebugPrint op -> read_op op
| Assign (var, op) | Deref (var, op) | Ref (var, op) ->
write_var var;
read_op op
| Add (var, op1, op2) | Sub (var, op1, op2) | TestEqual (var, op1, op2) ->
write_var var;
read_op op1;
read_op op2
| Call (var, _, args) ->
write_var var;
List.iter read_op args
| GetParam var -> write_var var
| Return opt_op -> Option.map read_op opt_op |> ignore);
Option.map write_var (Ir.kill_of ir) |> ignore;
List.iter read_op (Ir.gen_of ir);
check_for_changes ()

(** [pass work_list liveliness cfg bb] performs a single pass of liveliness
Expand Down
1 change: 1 addition & 0 deletions lib/frontend/ir_gen.ml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ let rec generate_expr ctx cfg block expr =
match op with
| Plus -> Ir.Add (result, lhs_result, rhs_result)
| Minus -> Ir.Sub (result, lhs_result, rhs_result)
| Times -> Ir.Mul (result, lhs_result, rhs_result)
| Equals -> Ir.TestEqual (result, lhs_result, rhs_result)
| _ -> failwith "not implemented"
in
Expand Down
22 changes: 20 additions & 2 deletions lib/ir/ir.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ type t =
| Assign of Variable.t * Operand.t
| Add of Variable.t * Operand.t * Operand.t
| Sub of Variable.t * Operand.t * Operand.t
| Mul of Variable.t * Operand.t * Operand.t
| Ref of Variable.t * Operand.t
| Deref of Variable.t * Operand.t
| TestEqual of Variable.t * Operand.t * Operand.t
Expand All @@ -14,13 +15,27 @@ let kill_of = function
| Assign (var, _)
| Add (var, _, _)
| Sub (var, _, _)
| Mul (var, _, _)
| Ref (var, _)
| Deref (var, _)
| TestEqual (var, _, _)
| GetParam var
| Call (var, _, _) -> Some var
| DebugPrint _ | Return _ -> None

let gen_of = function
| Assign (_, op)
| Ref (_, op)
| Deref (_, op)
| DebugPrint op
| Return (Some op) -> [ op ]
| Add (_, op1, op2)
| Sub (_, op1, op2)
| Mul (_, op1, op2)
| TestEqual (_, op1, op2) -> [ op1; op2 ]
| Call (_, _, ops) -> ops
| GetParam _ | Return None -> []

let to_string =
let open Printf in
function
Expand All @@ -32,6 +47,9 @@ let to_string =
| Sub (r, o1, o2) ->
sprintf "%s = %s - %s" (Variable.to_string r) (Operand.to_string o1)
(Operand.to_string o2)
| Mul (r, o1, o2) ->
sprintf "%s = %s * %s" (Variable.to_string r) (Operand.to_string o1)
(Operand.to_string o2)
| Ref (r, o) ->
sprintf "%s = &%s" (Variable.to_string r) (Operand.to_string o)
| Deref (r, o) ->
Expand All @@ -43,10 +61,10 @@ let to_string =
| Call (r, name, args) ->
sprintf "%s = %s(%s)" (Variable.to_string r)
(name |> String.concat "::")
(args |> List.map Operand.to_string |> String.concat ",")
(args |> List.map Operand.to_string |> String.concat ", ")
| GetParam var -> sprintf "%s = <next parameter>" (Variable.to_string var)
| Return op ->
sprintf "return %s"
sprintf "return%s"
(match op with
| Some op -> " " ^ Operand.to_string op
| None -> "")
4 changes: 4 additions & 0 deletions lib/ir/ir.mli
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ type t =
| Assign of Variable.t * Operand.t
| Add of Variable.t * Operand.t * Operand.t
| Sub of Variable.t * Operand.t * Operand.t
| Mul of Variable.t * Operand.t * Operand.t
| Ref of Variable.t * Operand.t
| Deref of Variable.t * Operand.t
| TestEqual of Variable.t * Operand.t * Operand.t
Expand All @@ -15,5 +16,8 @@ type t =
otherwise. *)
val kill_of : t -> Variable.t option

(** [gen_of ir] is a list of operands read from in [ir]. *)
val gen_of : t -> Operand.t list

(** [to_string ir] is a string representation of the IRk instruction [ir]. *)
val to_string : t -> string
4 changes: 4 additions & 0 deletions lib/ir/ir_sim.ml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ let rec run_cfg simulator cfgs cfg =
Context.insert simulator.context (Variable.to_string var)
(eval oper1 - eval oper2);
false
| Ir.Mul (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);
Expand Down
Loading

0 comments on commit 9b5b97f

Please sign in to comment.