Skip to content

Commit

Permalink
Function arguments work if you dont use more args than register params
Browse files Browse the repository at this point in the history
  • Loading branch information
ethanuppal committed May 11, 2024
1 parent dae6302 commit cba9cd5
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 50 deletions.
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-11 01:56:28.147911
> Last updated: 2024-05-11 02:29:04.778170
```
$ ./main -h
Expand Down
34 changes: 21 additions & 13 deletions lib/backend/asm_emit.ml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
let debug_print_symbol = "_x86istmb_debug_print"
let mangle name = "_x86istmb_" ^ name
let debug_print_symbol = mangle "debug_print"

let emit_var regalloc var =
match Ir.VariableMap.find regalloc var with
Expand All @@ -15,13 +16,14 @@ let emit_call text regalloc name args =
if List.length to_save mod 2 = 0 then to_save
else List.hd to_save :: to_save
in
let to_pass = [| Asm.Register.RDI; RSI; RDX; RCX; R8; R9 |] in
Asm.Section.add_all text
(List.map (fun r -> Asm.Instruction.Push (Register r)) to_save
@ [
(* double push for 16 byte alignment *)
Asm.Instruction.Mov (Register RDI, List.hd args |> emit_oper regalloc);
Call (Label name);
]
@ List.mapi
(fun i arg ->
Asm.Instruction.Mov (Register to_pass.(i), emit_oper regalloc arg))
args
@ [ Asm.Instruction.Call (Label name) ]
@ (List.map (fun r -> Asm.Instruction.Pop (Register r)) to_save |> List.rev)
)

Expand All @@ -44,9 +46,17 @@ let emit_ir text regalloc = function
| Ref _ -> failwith "ref not impl"
| Deref _ -> failwith "deref not impl"
| DebugPrint op -> emit_call text regalloc debug_print_symbol [ op ]
| Call _ -> failwith "TODO"
| Return op ->
Asm.Section.add text (Mov (Register RAX, emit_oper regalloc op))
| Call (var, name, args) ->
emit_call text regalloc (mangle name) args;
Asm.Section.add text (Mov (emit_var regalloc var, Register RAX))
| Return op_opt ->
Option.map
(fun op ->
Asm.Section.add text (Mov (Register RAX, emit_oper regalloc op)))
op_opt
|> ignore;
Asm.Section.add_all text
[ Mov (Register RSP, Register RBP); Pop (Register RBP); Ret ]

let emit_bb text cfg regalloc bb =
Asm.Section.add text
Expand Down Expand Up @@ -79,10 +89,8 @@ let emit_cfg ~text cfg regalloc =
[
Label
(Asm.Label.make ~is_global:true ~is_external:false
("_x86istmb_" ^ Cfg.name_of cfg));
(mangle (Cfg.name_of cfg)));
Push (Register RBP);
Mov (Register RBP, Register RSP);
];
Cfg.blocks_of cfg |> List.iter (emit_bb text cfg regalloc);
Asm.Section.add_all text
[ Mov (Register RSP, Register RBP); Pop (Register RBP); Ret ]
Cfg.blocks_of cfg |> List.iter (emit_bb text cfg regalloc)
6 changes: 4 additions & 2 deletions lib/backend/liveliness.ml
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,10 @@ let apply_rules liveliness analysis cfg bb ir ir_idx ~is_final =
write_var var;
read_op op1;
read_op op2
| Call (var, _) -> write_var var
| Return op -> read_op op);
| Call (var, _, args) ->
write_var var;
List.iter read_op args
| Return opt_op -> Option.map read_op opt_op |> ignore);
check_for_changes ()

(** [pass work_list liveliness cfg bb] performs a single pass of liveliness
Expand Down
4 changes: 0 additions & 4 deletions lib/frontend/analysis.ml
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,6 @@ let infer prog =
List.iter
(fun (name, ty) -> bind_name_to_type ctx name ty (Right stmt))
params;
let body =
if return = Type.unit_prim_type then body @ [ Return None ]
else body
in
if infer_body ctx return body <> Terminal then
raise (halt_error name (Right stmt));
Context.pop ctx
Expand Down
37 changes: 24 additions & 13 deletions lib/frontend/ir_gen.ml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ let rec generate_expr ctx cfg block expr =
in
Basic_block.add_ir block ir_instr;
Operand.make_var result
| Call _ -> failwith "no calls in ir gen"
| 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));
Operand.make_var call_result

(** [generate_stmt ctx cfg block stmt] adds IR for [stmt] (and potentially more
blocks) onto [block] in [cfg], and returns the block that program flow
Expand Down Expand Up @@ -88,21 +92,28 @@ let rec generate_stmt ctx cfg block = function
| ExprStatement expr ->
ignore (generate_expr ctx cfg block expr);
block
| Return _ -> failwith "ir gen need to gen return"
| Return expr_opt ->
(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));
block

and generate_stmt_lst ctx cfg block lst =
let block_ref = ref block in
List.iter (fun stmt -> block_ref := generate_stmt ctx cfg !block_ref stmt) lst;
!block_ref

let generate prog =
match prog with
| Function { name = "main"; params; return; body } :: _ ->
if not (List.is_empty params) then failwith "fix params in ir gen";
if return <> Type.unit_prim_type then failwith "fix return in ir gen";
let ctx = Context.make () in
Context.push ctx;
let cfg = Cfg.make "main" in
ignore (generate_stmt_lst ctx cfg (Cfg.entry_to cfg) body);
[ cfg ]
| _ -> failwith "not implemented"
let generate =
List.map (fun stmt ->
match stmt with
| Function { name; params; return; body } ->
if not (List.is_empty params) then failwith "fix params in ir gen";
if return <> Type.unit_prim_type then failwith "fix return in ir gen";
let ctx = Context.make () in
Context.push ctx;
let cfg = Cfg.make name in
ignore (generate_stmt_lst ctx cfg (Cfg.entry_to cfg) body);
cfg
| _ -> failwith "?")
23 changes: 20 additions & 3 deletions lib/frontend/parse_lex.ml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,23 @@ let lex_and_parse ?(filename = "<stdin>") input =
let parse lexbuf = Parser.main Lexer.read lexbuf in
let lexbuf = Lexing.from_string ~with_positions:true input in
Lexing.set_filename lexbuf filename;
try parse lexbuf with
| Parser.Error -> raise (ParserError (syntax_error_msg lexbuf))
| Lexer.LexerError err -> raise (ParserError err)
let prog =
try parse lexbuf with
| Parser.Error -> raise (ParserError (syntax_error_msg lexbuf))
| Lexer.LexerError err -> raise (ParserError err)
in
List.map
(fun stmt ->
match stmt with
| Ast.Function { name; params; return; body } ->
Ast.Function
{
name;
params;
return;
body =
(if return = Type.unit_prim_type then body @ [ Return None ]
else body);
}
| other -> other)
prog
17 changes: 12 additions & 5 deletions lib/ir/ir.ml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ type t =
| Deref of Variable.t * Operand.t
| TestEqual of Variable.t * Operand.t * Operand.t
| DebugPrint of Operand.t
| Call of Variable.t * string
| Return of Operand.t
| Call of Variable.t * string * Operand.t list
| Return of Operand.t option

(** [kill_of ir] is [Some var] if [var] is assigned to in [ir] and [None]
otherwise. *)
Expand All @@ -23,7 +23,8 @@ let kill_of = function
| Ref (var, _)
| Deref (var, _)
| TestEqual (var, _, _) -> Some var
| DebugPrint _ | Call _ | Return _ -> None
| Call (var, _, _) -> Some var
| DebugPrint _ | Return _ -> None

let to_string =
let open Printf in
Expand All @@ -44,5 +45,11 @@ let to_string =
sprintf "%s = %s == %s" (Variable.to_string r) (Operand.to_string o1)
(Operand.to_string o2)
| DebugPrint op -> sprintf "debug_print %s" (Operand.to_string op)
| Call (r, name) -> sprintf "%s = %s()" (Variable.to_string r) name
| Return op -> sprintf "return %s" (Operand.to_string op)
| Call (r, name, args) ->
sprintf "%s = %s(%s)" (Variable.to_string r) name
(args |> List.map Operand.to_string |> String.concat ",")
| Return op ->
sprintf "return%s"
(match op with
| Some op -> " " ^ Operand.to_string op
| None -> "")
19 changes: 10 additions & 9 deletions lib/user/driver.ml
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,17 @@ let compile paths _ build_dir_loc =
let statements = Parse_lex.lex_and_parse ~filename:source_path source in
Analysis.infer statements;
let cfgs = Ir_gen.generate statements in
let main_cfg = List.hd cfgs in
let liveliness_analysis = Liveliness.analysis_of main_cfg in
let instr_ordering = InstrOrdering.make main_cfg in
let regalloc =
Regalloc.allocate_for main_cfg liveliness_analysis instr_ordering
in
let text_section = Asm.Section.make "text" 16 in
Asm_emit.emit_preamble ~text:text_section;
Asm_emit.emit_cfg ~text:text_section main_cfg regalloc;
List.iter
(fun cfg ->
let liveliness_analysis = Liveliness.analysis_of cfg in
let instr_ordering = InstrOrdering.make cfg in
let regalloc =
Regalloc.allocate_for cfg liveliness_analysis instr_ordering
in
Asm_emit.emit_cfg ~text:text_section cfg regalloc)
cfgs;
let asm_file = Asm.AssemblyFile.make () in
Asm.AssemblyFile.add asm_file text_section;
let asm_output_path =
Expand Down Expand Up @@ -82,8 +84,7 @@ let compile paths _ build_dir_loc =
"./a.out\n"); *)
if
Sys.command
(Printf.sprintf "cd %s/ && " build_dir
^ cmd_prefix ^ "make build 2>/dev/null")
(Printf.sprintf "cd %s/ && " build_dir ^ cmd_prefix ^ "make build")
<> 0
then failwith "compilation failed";
Printf.printf "==> Wrote build files to %s\n" build_dir;
Expand Down
7 changes: 7 additions & 0 deletions source/demo.x86istmb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
func peace_love() {
print 3110
}

func main() {
peace_love()
}
7 changes: 7 additions & 0 deletions source/peacelove3110.x86istmb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
func peace_love() {
print 3110
}

func main() {
peace_love()
}

0 comments on commit cba9cd5

Please sign in to comment.