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

Integer Multiplication Optimization #46

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
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-16 03:05:51.632480
> Last updated: 2024-05-16 09:59:47.289578

```
$ ./main -h
Expand Down
9 changes: 9 additions & 0 deletions lib/backend/asm.ml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ module Instruction = struct
| Syscall
| Label of Label.t
| DataBytes of int list
| Shl of Operand.t * Operand.t
| Shr of Operand.t * Operand.t
| Sar of Operand.t * Operand.t

let to_nasm = function
| Mov (op1, op2) ->
Expand All @@ -131,6 +134,12 @@ module Instruction = struct
| Label label -> Label.to_nasm label
| DataBytes data ->
"db " ^ (data |> List.map string_of_int |> String.concat ", ")
| Shl (op1, op2) ->
"shl " ^ Operand.to_nasm op1 ^ ", " ^ Operand.to_nasm op2
| Shr (op1, op2) ->
"shr " ^ Operand.to_nasm op1 ^ ", " ^ Operand.to_nasm op2
| Sar (op1, op2) ->
"sar " ^ Operand.to_nasm op1 ^ ", " ^ Operand.to_nasm op2
end

module Section = struct
Expand Down
3 changes: 3 additions & 0 deletions lib/backend/asm.mli
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ module Instruction : sig
| Syscall
| Label of Label.t
| DataBytes of int list
| Shl of Operand.t * Operand.t
| Shr of Operand.t * Operand.t
| Sar of Operand.t * Operand.t

(** [to_nasm instr] is the NASM representation of [instr]. *)
val to_nasm : t -> string
Expand Down
18 changes: 18 additions & 0 deletions lib/backend/asm_emit.ml
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,24 @@ let emit_ir text_section data_section regalloc param_ctx = function
Mov (emit_var regalloc var, emit_oper regalloc data_section op);
IMul (emit_var regalloc var, emit_oper regalloc data_section op2);
]
| Shl (var, op, op2) ->
Asm.Section.add_all text_section
[
Mov (emit_var regalloc var, emit_oper regalloc data_section op);
Shl (emit_var regalloc var, emit_oper regalloc data_section op2);
]
| Shr (var, op, op2) ->
Asm.Section.add_all text_section
[
Mov (emit_var regalloc var, emit_oper regalloc data_section op);
Shr (emit_var regalloc var, emit_oper regalloc data_section op2);
]
| Sar (var, op, op2) ->
Asm.Section.add_all text_section
[
Mov (emit_var regalloc var, emit_oper regalloc data_section op);
Sar (emit_var regalloc var, emit_oper regalloc data_section op2);
]
| Ref _ -> failwith "ref not impl"
| Deref _ -> failwith "deref not impl"
| DebugPrint op ->
Expand Down
8 changes: 8 additions & 0 deletions lib/frontend/context.mli
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ val get_local : 'a t -> string -> 'a option
a scope. Scopes that were pushed later are earlier in the result. *)
val to_list : 'a t -> (string * 'a) list list

(** [add_namespace ctx name] adds a namespace [name] to the context [ctx]. The
namespace is added to the top of the namespace stack in the context. *)
val add_namespace : 'a t -> string -> unit

(** [pop_namespace ctx] pops the top namespace from the given context [ctx]. It
updates the namespace field of [ctx] by removing the first element. *)
val pop_namespace : 'a t -> unit

(** [in_namespace ctx symbol] returns the list of symbols in the namespace of
[ctx] with [symbol] included. The symbols are returned in reverse order. *)
val in_namespace : 'a t -> string -> string list
5 changes: 5 additions & 0 deletions lib/ir/basic_block.mli
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,9 @@ val equal : t -> t -> bool
[bb1 = bb2]. *)
val hash : t -> int

(** [to_string bb] returns a string representation of the basic block [bb]. The
string representation includes the label of the basic block, followed by the
string representation of each instruction in the basic block. If the basic
block has a branch condition, it is also included in the string
representation. *)
val to_string : t -> string
1 change: 1 addition & 0 deletions lib/ir/id.mli
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@ module Gen : sig
generator; see [make]. *)
val next : t -> id

(** [hard_reset ()] resets the global value to 0. *)
val hard_reset : unit -> unit
end
18 changes: 18 additions & 0 deletions lib/ir/ir.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ type 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
| Shl of Variable.t * Operand.t * Operand.t
| Shr of Variable.t * Operand.t * Operand.t
| Sar 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 @@ -16,6 +19,9 @@ let kill_of = function
| Add (var, _, _)
| Sub (var, _, _)
| Mul (var, _, _)
| Shl (var, _, _)
| Shr (var, _, _)
| Sar (var, _, _)
| Ref (var, _)
| Deref (var, _)
| TestEqual (var, _, _)
Expand All @@ -32,6 +38,9 @@ let gen_of = function
| Add (_, op1, op2)
| Sub (_, op1, op2)
| Mul (_, op1, op2)
| Shl (_, op1, op2)
| Shr (_, op1, op2)
| Sar (_, op1, op2)
| TestEqual (_, op1, op2) -> [ op1; op2 ]
| Call (_, _, ops) -> ops
| GetParam _ | Return None -> []
Expand All @@ -50,6 +59,15 @@ let to_string =
| Mul (r, o1, o2) ->
sprintf "%s = %s * %s" (Variable.to_string r) (Operand.to_string o1)
(Operand.to_string o2)
| Shl (r, o1, o2) ->
sprintf "%s = %s << %s" (Variable.to_string r) (Operand.to_string o1)
(Operand.to_string o2)
| Shr (r, o1, o2) ->
sprintf "%s = %s >> %s" (Variable.to_string r) (Operand.to_string o1)
(Operand.to_string o2)
| Sar (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 Down
3 changes: 3 additions & 0 deletions lib/ir/ir.mli
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ type 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
| Shl of Variable.t * Operand.t * Operand.t
| Shr of Variable.t * Operand.t * Operand.t
| Sar 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 Down
12 changes: 12 additions & 0 deletions lib/ir/ir_sim.ml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ let rec run_cfg simulator cfgs cfg =
Context.insert simulator.context (Variable.to_string var)
(Left (eval_int oper1 * eval_int oper2));
false
| Ir.Shl (var, oper1, oper2) ->
Context.insert simulator.context (Variable.to_string var)
(Left (eval_int oper1 lsl eval_int oper2));
false
| Ir.Shr (var, oper1, oper2) ->
Context.insert simulator.context (Variable.to_string var)
(Left (eval_int oper1 lsr eval_int oper2));
false
| Ir.Sar (var, oper1, oper2) ->
Context.insert simulator.context (Variable.to_string var)
(Left (eval_int oper1 asr eval_int oper2));
false
| Ir.TestEqual (var, oper1, oper2) ->
Context.insert simulator.context (Variable.to_string var)
(if eval oper1 = eval oper2 then Left 1 else Left 0);
Expand Down
1 change: 1 addition & 0 deletions lib/ir/ir_sim.mli
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ val run : t -> Cfg.t list -> unit
human-readable string. *)
val output_of : t -> string

(** [clear_output simulator] clears the output of the simulator. *)
val clear_output : t -> unit
3 changes: 1 addition & 2 deletions lib/ir/map/variableMap.mli
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@

include Hashtbl.S with type key = Variable.t
include Hashtbl.S with type key = Variable.t
25 changes: 25 additions & 0 deletions lib/ir/passes.ml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ module ConstFold : Pass.Sig = struct
| Sub (var, Operand.Constant lhs, Operand.Constant rhs) ->
Basic_block.set_ir bb i
(Ir.Assign (var, Operand.make_const (lhs - rhs)))
| Mul (var, Operand.Constant lhs, Operand.Constant rhs) ->
Basic_block.set_ir bb i
(Ir.Assign (var, Operand.make_const (lhs * rhs)))
| _ -> ()
done

Expand Down Expand Up @@ -62,6 +65,28 @@ module DeadCode : Pass.Sig = struct
let pass = Pass.make dead_code
end

module IntMult : Pass.Sig = struct
let is_power_of_two x = x > 0 && x land (x - 1) = 0

let log2 x =
let rec aux n acc = if acc >= x then n else aux (n + 1) (acc * 2) in
aux 0 1

let int_mult (bb, _) =
for i = 0 to Basic_block.length_of bb - 1 do
match Basic_block.get_ir bb i with
| Mul (var, Operand.Constant lhs, Operand.Variable rhs)
| Mul (var, Operand.Variable rhs, Operand.Constant lhs)
when is_power_of_two lhs ->
let shift_amount = log2 lhs in
Basic_block.set_ir bb i
(Ir.Shl (var, Operand.Variable rhs, Operand.Constant shift_amount))
| _ -> ()
done

let pass = Pass.make int_mult
end

let apply passes cfg liveliness =
let apply_pass pass bb =
Pass.execute pass bb (IdMap.find liveliness (Basic_block.id_of bb))
Expand Down
5 changes: 5 additions & 0 deletions lib/ir/passes.mli
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ module CopyProp : Pass.Sig
(** Dead code elimination optimization pass. *)
module DeadCode : Pass.Sig

(** Integer multiplication optimization pass. *)
module IntMult : Pass.Sig

(** Liveness analysis pass. *)

(** [apply passes cfg liveliness] applies each pass in [passes] to [cfg] in
order, using the liveliness information for [cfg] ([liveliness]).

Expand Down
7 changes: 6 additions & 1 deletion lib/user/driver.ml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,12 @@ let compile paths flags build_dir_loc =
Passes.apply
[
Passes.DeadCode.pass;
Pass.sequence Passes.CopyProp.pass Passes.ConstFold.pass
Pass.combine
[
Passes.CopyProp.pass;
Passes.ConstFold.pass;
Passes.IntMult.pass;
]
|> Pass.repeat 10;
]
cfg liveliness_analysis;
Expand Down
13 changes: 11 additions & 2 deletions lib/user/driver.mli
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
(** [main argv] *)
(** [main argv] is the entry point of the program. It takes in a string array
[argv] and returns [unit]. The function parses the command line arguments
using [Cli.parse], and then dispatches the appropriate action based on the
parsed result. *)
val main : string array -> unit

(** [compile paths flags build_dir_loc] *)
(** [compile paths flags build_dir_loc] compiles the given list of paths into an
executable.

[paths] is a list of file paths to be compiled. [flags] is a list of
compiler flags. [build_dir_loc] is an optional build directory location.

Raises [Failure] if the file extensions are not .x or .x86istmb. *)
val compile : string list -> Cli.flag list -> string option -> unit
8 changes: 7 additions & 1 deletion test/test_passes.ml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,15 @@ let fixed_ir_opts_tests =
([ Passes.ConstFold.pass ], "const fold ir opt");
([ Passes.CopyProp.pass ], "copy prop ir opt");
([ Passes.DeadCode.pass ], "dead code ir opt");
([ Passes.IntMult.pass ], "int mult ir opt");
( [
Pass.combine
[ Passes.ConstFold.pass; Passes.CopyProp.pass; Passes.DeadCode.pass ];
[
Passes.ConstFold.pass;
Passes.CopyProp.pass;
Passes.DeadCode.pass;
Passes.IntMult.pass;
];
],
"combined ir opt" );
( [
Expand Down