Skip to content

Commit

Permalink
Add x86 code generation
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisLane committed Nov 18, 2016
1 parent ba9c07b commit 202992d
Show file tree
Hide file tree
Showing 6 changed files with 254 additions and 13 deletions.
16 changes: 16 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM ocaml/opam:alpine

USER root

ENV OPAMYES=1

RUN apk add --no-cache git gcc m4 && \
opam init && \
opam install ocamlfind menhir && \
eval `opam config env` && \
git clone https://github.com/ChrisLane/Compiler-Construction /compiler && \
cd /compiler && \
make && \
apk del --no-cache git

WORKDIR /compiler
8 changes: 8 additions & 0 deletions compileandrun.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash

make
./main codegenx86 test.src > test.s
gcc -c test.s -o test.o
gcc test.o -o test
./test
rm -rf test.o test
59 changes: 59 additions & 0 deletions src/main/assembly.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
let codegenx86_prefix = "
.file \"template.c\"
.section .rodata
.LC0:
.string \"%d\\n\"
.text
.globl print
.type print, @function
print:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %edi
call exit
.cfi_endproc
.LFE0:
.size print, .-print
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $260, -4(%rbp)
movl -4(%rbp), %eax
// Begin injected code
"

let codegenx86_suffix = "
// End injected code
popq %rdi
call print
movl $1, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size main, .-main
.ident \"GCC: (GNU) 6.2.1 20160830\"
.section .note.GNU-stack,\"\",@progbits
"
137 changes: 137 additions & 0 deletions src/main/codegenx86.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
open Ast
open Assembly
open Buffer

let code = create 25
let sp = ref 0
let addr_base = ref 0

(* Generate a string for the int value of a bool *)
let string_int_of_bool n = if n then string_of_int 1 else string_of_int 0

(* The string for instructions of operators *)
let instruction_of_op = function
| Plus -> "\taddq\t%rbx, %rax\n"
| Minus -> "\tsubq\t%rbx, %rax\n"
| Times -> "\timulq\t%rbx\n"
| Divide -> "\tmovq\t$0, %rdx\n" ^ "\tidivq\t%rbx\n"
| Leq -> "\tcmpq\t%rbx, %rax\n" ^ "\tsetle\t%al\n" ^ "\tmovzbq\t%al, %rax\n"
| Geq -> "\tcmpq\t%rbx, %rax\n" ^ "\tsetge\t%al\n" ^ "\tmovzbq\t%al, %rax\n"
| Equal -> "\tcmpq\t%rbx, %rax\n" ^ "\tsete\t%al\n" ^ "\tmovzbq\t%al, %rax\n"
| Noteq -> "\tcmpq\t%rbx, %rax\n" ^ "\tsetne\t%al\n" ^ "\tmovzbq\t%al, %rax\n"
| And -> "\tandq\t%rbx, %rax\n"
| Or -> "\torq\t%rbx, %rax\n"
| _ -> failwith "Operator not implemented."

(* Instructions for a const *)
let codegenx86_const n =
"\tpushq\t$" ^ (string_of_int n) ^ "\n"
|> add_string code

(* Instructions for a bool*)
let codegenx86_bool n =
"\tpushq\t$" ^ (string_int_of_bool n) ^ "\n"
|> add_string code

(* Instructions for an operator *)
let codegenx86_op op =
"\tpopq\t%rbx\n" ^
"\tpopq\t%rax\n" ^
(instruction_of_op op) ^
"\tpushq\t%rax\n"
|> add_string code

(* Instructions for an identifier *)
let codegenx86_id addr =
"\t//offset " ^ (string_of_int addr) ^ "\n" ^
"\tmov " ^ (-16 -8 * addr |> string_of_int) ^ "(%rbp), %rax\n" ^
"\tpush %rax\n"
|> add_string code

(* Instructions for a let *)
let codegenx86_let _ =
"\tpopq\t%rax\n" ^
"\tpopq\t%rbx\n" ^
"\tpushq\t%rax\n"
|> add_string code

(* Instructions for assignment *)
let codegenx86_asg _ =
"\tpopq\t%rbx\n" ^
"\tpopq\t%rax\n" ^
"\tmovq\t%rbx, (%rax)\n"
|> add_string code

(* Instructions for dereferencing *)
let codegenx86_deref _ =
"\tpopq\t%rbx\n" ^
"\tmovq\t(%rbx), %rax)\n" ^
"\tpushq\t%rax\n"
|> add_string code

(* Instructions for print *)
let codegenx86_print _ =
"\tpopq\t%rdi\n" ^
"\tcall\tprint\n"
|> add_string code

(* Lookup the address for a value *)
let rec lookup x = function
| [] -> failwith "Could not find symbol address."
| (y, addr)::ys when x = y -> addr
| _::ys -> lookup x ys

(* Generate x86 code for expressions *)
let rec codegenx86 symt = function
| Empty -> "\tnop\n" |> add_string code
| Operator (op, e1, e2) ->
codegenx86 symt e1;
codegenx86 symt e2;
codegenx86_op op;
sp := !sp -1
| Identifier x ->
let addr = lookup x symt in
codegenx86_id (addr);
sp := !sp + 1
| Const n ->
codegenx86_const n;
sp := !sp + 1
| Bool n ->
codegenx86_bool n;
sp := !sp + 1
| Let (x, e1, e2) ->
codegenx86 symt e1;
codegenx86 ((x, !sp) :: symt) e2;
codegenx86_let ();
sp := !sp - 1
| Seq (e, Empty) -> codegenx86 symt e
| Seq (e1, e2) ->
let _ = codegenx86 symt e1 in
codegenx86 symt e2
| Asg (e1, e2) ->
codegenx86 symt e1;
codegenx86 symt e2;
codegenx86_asg ()
| Deref n ->
codegenx86 symt n;
codegenx86_deref ()
| Print n ->
codegenx86 symt n;
codegenx86_print ()
| _ -> failwith "Unimplemented expression."

(* Generate x86 code for a function *)
let codegenx86_func func =
reset code;
add_string code codegenx86_prefix;
addr_base := 0;
codegenx86 [] func;
add_string code codegenx86_suffix;
output_buffer stdout code;
""

(* Generate x86 code for a program *)
let rec codegenx86_prog = function
| [] -> failwith "Codegenx86 requires a 'main' function."
| Fundef ("main", args, body)::ys -> codegenx86_func body
| _::ys -> codegenx86_prog ys
30 changes: 17 additions & 13 deletions src/main/main.ml
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,28 @@ let print_help () =
print_endline ("\t'evaluate' - Evaluate a source file.");
print_endline ("\t'interpret' - Interpret a source file.");
print_endline ("\t'codegen' - Generate code from a source file.");
print_endline ("\t'codegenx86' Generate x86 code from a source file.");
print_endline ("==================================================");
print_endline ""

(* Run the appropriate command *)
let run_task task optimise file = match task with
| "parse" -> (match optimise with
| true -> Print.parse_file_optimised file
| false -> Print.parse_file file)
| "evaluate" -> (match optimise with
| true -> Print.eval_file_optimised file
| false -> Print.eval_file file)
| "interpret" -> (match optimise with
| true -> Print.interpret_file_optimised file
| false -> Print.interpret_file file)
| "codegen" -> (match optimise with
| true -> Print.codegen_file_optimised file
| false -> Print.codegen_file file)
| _ -> print_endline "\nInvalid task."; print_help(); exit 1
| "parse" -> (match optimise with
| true -> Print.parse_file_optimised file
| false -> Print.parse_file file)
| "evaluate" -> (match optimise with
| true -> Print.eval_file_optimised file
| false -> Print.eval_file file)
| "interpret" -> (match optimise with
| true -> Print.interpret_file_optimised file
| false -> Print.interpret_file file)
| "codegen" -> (match optimise with
| true -> Print.codegen_file_optimised file
| false -> Print.codegen_file file)
| "codegenx86" -> (match optimise with
| true -> Print.codegenx86_file_optimised file
| false -> Print.codegenx86_file file)
| _ -> print_endline "\nInvalid task."; print_help(); exit 1

(* If more/less than 2 arguement is given, print proper command usage *)
let _ = match Array.length Sys.argv with
Expand Down
17 changes: 17 additions & 0 deletions src/main/print.ml
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,20 @@ let codegen_file_optimised filename = open_in filename
|> Codegen.codegen_prog
|> print_string
|> print_newline

(* Parse, codegenx86 and print a return value if successful *)
let codegenx86_file filename = open_in filename
|> Lexing.from_channel
|> Error.parse_with_error
|> Codegenx86.codegenx86_prog
|> print_string
|> print_newline

(* Parse, optimise, codegenx86 and print a return value if successful *)
let codegenx86_file_optimised filename = open_in filename
|> Lexing.from_channel
|> Error.parse_with_error
|> Optim.optim_program
|> Codegenx86.codegenx86_prog
|> print_string
|> print_newline

0 comments on commit 202992d

Please sign in to comment.