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

Ps 2 compile #73

Merged
merged 39 commits into from
Oct 3, 2011
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
a3fb524
Changed definition of operand
awatanabe Sep 29, 2011
e282848
Partial implementation of compile_exp_r
awatanabe Sep 29, 2011
dd04af0
Preliminary implementation of compile_exp
awatanabe Sep 29, 2011
75ae0c1
Preliminary implementation of compile_exp
awatanabe Sep 29, 2011
b8c3656
Added comments to compile_exp
awatanabe Sep 30, 2011
e317019
Updated implementation of revapp to make it more logical
awatanabe Sep 30, 2011
9a64585
Implemented compilation of if statements
awatanabe Sep 30, 2011
337fceb
Added compilation for for loop and while loop
awatanabe Sep 30, 2011
1681d9c
Added a few comments
awatanabe Sep 30, 2011
5f6e407
Minor changes to the build system and a nice stub for the test system…
spartango Oct 2, 2011
eb312ed
pulled in stuff from compile to be able to adequately test it
spartango Oct 2, 2011
e2a1c09
added a nice script to compile the canned tests
spartango Oct 2, 2011
f8ec6df
got a working way to compile tests and hijack them with prints
spartango Oct 2, 2011
cf4ce9f
added some glue to run tests as a batch
spartango Oct 2, 2011
7001f26
made outputs nicer
spartango Oct 2, 2011
5d9a8a8
pretty\!
spartango Oct 2, 2011
31e2a41
starting some simple variable collection tests
spartango Oct 2, 2011
2bb37ca
fixed a bug in nested assignment
spartango Oct 2, 2011
d5dfd70
added a hack that patches the fail that is the inability for SPIM to …
spartango Oct 2, 2011
13a4759
cleanliness included in the hack
spartango Oct 2, 2011
191f705
Minor changes as i hunt down the flipped sw/la bug
spartango Oct 2, 2011
2b7776d
CAUTIOUS COMMIT: passes tests with the bug fix, but i'm still not con…
spartango Oct 2, 2011
9f86b33
Merge pull request #68 from spartango/ps_2_tests
spartango Oct 2, 2011
24cc9b6
added a file for optimizations
spartango Oct 2, 2011
25fa78d
minor changes
spartango Oct 2, 2011
52d622e
preliminary implementation of jump threading
spartango Oct 2, 2011
1b61aee
jump threading appears to work, although its vulnerable to crazy loop…
spartango Oct 2, 2011
0299fcb
nice things in .gitignore
spartango Oct 2, 2011
975b033
starting constantfolding, added folder and expression stub
spartango Oct 3, 2011
0f40e29
all cases by and/or in place
spartango Oct 3, 2011
5faea13
constant folder compiles, moving to test
spartango Oct 3, 2011
92dbb2d
added a simple constant folding fish file
spartango Oct 3, 2011
934e4af
added a simple constant folding test
spartango Oct 3, 2011
c5d34ef
Merge pull request #70 from spartango/ps_2_jump_thread
spartango Oct 3, 2011
0a81a8f
minor change to not folding
spartango Oct 3, 2011
bce120f
added a nice benchmark script
spartango Oct 3, 2011
0e786a5
better display
spartango Oct 3, 2011
8341f1f
used a fold in good place
spartango Oct 3, 2011
b2bacce
Merge pull request #72 from spartango/ps_2_conditional_opt
spartango Oct 3, 2011
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
22 changes: 22 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,25 @@ ps1/.paths
ps0/test.asm

ps1/.settings/org.eclipse.core.resources.prefs

ps2/word32.cmo

ps2/ps2

ps2/parse.mli

ps2/parse.cmi

ps2/compiled_tests

ps2/*.cmo

ps2/*.cmi

ps2/tests

ps2/parse.output

ps2/parse.ml

ps2/lex.ml
20 changes: 15 additions & 5 deletions ps2/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,20 @@
# change to a different ocamlc if you prefer (e.g., ocamlopt)
COMPILER=ocamlc

all: clean compile
all: clean compile test run_tests

test: mips
test: compile
./tests

compile_tests: compile
./compile_canned.sh

run_tests: compile_tests
./run_tests.sh

benchmark: compile_tests
./benchmark.sh

compile:
$(COMPILER) -c ast.ml
ocamlyacc -v parse.mly
Expand All @@ -19,13 +28,14 @@ compile:
$(COMPILER) -c eval.ml
$(COMPILER) -c word32.ml
$(COMPILER) -c mips.ml
$(COMPILER) -c optimize.ml
$(COMPILER) -c compile.ml
$(COMPILER) -c fish.ml
$(COMPILER) -c pretty_print.ml
$(COMPILER) -c test_framework.ml
$(COMPILER) -c compile_tests.ml
$(COMPILER) -o ps2 ast.cmo parse.cmo lex.cmo eval.cmo word32.cmo mips.cmo compile.cmo fish.cmo
$(COMPILER) -o tests ast.cmo parse.cmo lex.cmo eval.cmo word32.cmo mips.cmo compile.cmo pretty_print.cmo test_framework.cmo compile_tests.cmo
$(COMPILER) -o ps2 ast.cmo parse.cmo lex.cmo eval.cmo word32.cmo mips.cmo optimize.cmo compile.cmo fish.cmo
$(COMPILER) -o tests ast.cmo parse.cmo lex.cmo eval.cmo word32.cmo mips.cmo optimize.cmo compile.cmo pretty_print.cmo test_framework.cmo compile_tests.cmo

clean:
-rm *.cmo *.cmi ps2 parse.ml parse.mli lex.ml tests parse.output
rm -rf *.cmo *.cmi ps2 parse.ml parse.mli lex.ml tests parse.output compiled_tests
22 changes: 22 additions & 0 deletions ps2/benchmark.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/sh

echo "[==========] Benchmarking Canned Tests"

if [[ -e compiled_tests ]]; then
for test_file in `ls compiled_tests/*_test.asm`; do
echo "\x1b\x5b1;36m[ RUNNING ]\x1b\x5b0m ${test_file:15}"
log_file=${test_file%.asm}.log
(time ./spim_run.sh $test_file > $log_file) 2>> $log_file
count=`wc -l $log_file | awk '{print $1}'`
if (($count > 6)); then
# Something has failed, we'll log out and return a nice fail message
echo "\x1b\x5b1;31m[ FAILED ]\x1b\x5b0m See $log_file for error message"
else
echo "\x1b\x5b1;32m[ COMPLETE ]\x1b\x5b0m Time:" `tail -n 2 $log_file | head -n 1`
fi
done
else
echo "\x1b\x5b1;31m[ ERROR ]\x1b\x5b0m: Compiled Tests not found"
fi

echo "[==========] Completed"
127 changes: 113 additions & 14 deletions ps2/compile.ml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
(* Compile Fish AST to MIPS AST *)
open Mips
open Ast
open Optimize

exception IMPLEMENT_ME

Expand All @@ -9,7 +10,7 @@ type result = { code : Mips.inst list;

(* generate fresh labels *)
let label_counter = ref 0
let new_int() = (label_counter := (!label_counter) + 1; !label_counter)
let new_int() = (label_counter := (!label_counter) + 1; !label_counter)
let new_label() = "L" ^ (string_of_int (new_int()))

(* sets of variables -- Ocaml Set and Set.S *)
Expand All @@ -24,6 +25,9 @@ let variables : VarSet.t ref = ref (VarSet.empty)
let add_var (v: string) : unit =
variables := VarSet.add v (!variables); ()

let find_var (v: string) : bool =
VarSet.exists (fun x -> x = v) !variables

(* generate a fresh temporary variable and store it in the variables set. *)
let rec new_temp() : string=
let t = "T" ^ (string_of_int (new_int())) in
Expand All @@ -37,20 +41,21 @@ let reset() = (label_counter := 0; variables := VarSet.empty)
(* find all of the variables in a program and add them to
* the set variables *)
let rec collect_vars (p : Ast.program) : unit =
(*************************************************************)
let stip_pos r = let(v,_) = r in v in
let rec collect_vars_e (e: Ast.exp) : unit =
match (stip_pos e) with
| Var v -> add_var v
| Assign (v, e1) -> add_var v
| Var v -> add_var ("V"^v)
| Assign (v, e1) ->
let _ = add_var ("V"^v) in collect_vars_e e1
| Int _ -> ()
| Binop(e1, _, e2) -> collect_vars_e e1;
collect_vars_e e2
| Not e -> collect_vars_e e;
| And (e1, e2) -> collect_vars_e e1;
collect_vars_e e2
| Or (e1, e2) -> collect_vars_e e1;
collect_vars_e e2 in
collect_vars_e e2
in
match (stip_pos p) with
| Exp e -> collect_vars_e e
| Seq (s1, s2) -> collect_vars s1;
Expand All @@ -65,29 +70,123 @@ let rec collect_vars (p : Ast.program) : unit =
collect_vars_e e3;
collect_vars s
| Return e -> collect_vars_e e
(*************************************************************)

(* Prepends reversed x onto accum. Order of parameters for
* readability of code *)
let rec revapp (accum: 'a list) (x: 'a list) : 'a list=
match x with
| [] -> accum
| head::tail -> revapp (head::accum) tail

let rev x = revapp [] x

(* Factors out common code for compiling two nested expressions and
* carrying out some instruction. The result of e1 is stored in R3,
* the result of e2 in R2. in is the instruction to carry out on these
* results *)
let rec compile_exp_r (is: inst list) ((e,_): Ast.exp): inst list =
let dual_op (e1: Ast.exp) (e2: Ast.exp) (instruction: inst) : inst list =
let t = new_temp() in
(* Load result of first expression and carry out instruction *)
revapp (compile_exp_r
(revapp (compile_exp_r is e1) [La(R3, t); Sw(R2, R3, Int32.zero)])
e2)
[La(R3, t); Lw(R3, R3, Int32.zero); instruction] in
match e with
| Var v -> revapp is [La(R2, "V"^v); Lw(R2,R2, Int32.zero)]
| Int i -> Li(R2, Word32.fromInt i)::is
| Binop(e1,op,e2) ->
let oper = (match op with
| Plus -> Mips.Add(R2, R3, Reg(R2))
| Minus -> Mips.Sub(R2, R3, R2)
| Times -> Mips.Mul(R2, R3, R2)
| Div -> Mips.Div(R2, R3, R2)
| Eq -> Mips.Seq(R2, R3, R2)
| Neq -> Mips.Sne(R2, R3, R2)
| Lt -> Mips.Slt(R2, R3, R2)
| Lte -> Mips.Sle(R2, R3, R2)
| Gt -> Mips.Sgt(R2, R3, R2)
| Gte -> Mips.Sge(R2, R3, R2)) in
dual_op e1 e2 oper
(* If R3 = 0, then set R2 = 1, else R2 = 0 *)
| Not(e) -> revapp (compile_exp_r is e) [Mips.Seq(R2, R3, R0)]
| And(e1, e2) ->
dual_op e1 e2 (Mips.And(R2, R2, Reg R3))
| Or(e1, e2) ->
dual_op e1 e2 (Mips.Or(R2, R2, Reg R3))
| Assign(v, e) -> revapp (compile_exp_r is e) [La(R3, "V"^v); Sw(R2,R3, Int32.zero)]

(* Compiles a statement in reverse order *)
let rec compile_stmt_r (is: inst list) ((s,pos): Ast.stmt) : inst list =
match s with
(* Using compile_exp_r directly eliminates redundant reversing the list *)
| Exp e -> compile_exp_r is e
| Seq (s1, s2) ->
compile_stmt_r (compile_stmt_r is s1) s2
| If(e, then_s, else_s) ->
(* Test e, branch to else_s if not equal *)
let else_l = new_label () in
let end_l = new_label () in
revapp (compile_exp_r is e)
(rev (revapp
(compile_stmt_r
(revapp
(compile_stmt_r [Beq(R2,R0,else_l)] then_s)
[J(end_l); Label(else_l)]
)
else_s)
[Label(end_l)]))
| While(e, s) ->
let test_l = new_label () in
let top_l = new_label () in
revapp
(compile_exp_r (
revapp
(compile_stmt_r
(revapp is [J(test_l); Label(top_l)])
s)
[Label(test_l)])
e)
[Bne(R2,R0,top_l)]
(* Transform for loops into while loops *)
| For(e1, e2, e3, s) ->
(* Helper to get position out of statement *)
let get_pos s = let (_,p) = s in p in
(* Nastiness due to necesity of having position informaiton *)
compile_stmt_r is ((Ast.Seq(
(Ast.Exp e1, (get_pos e1)),
(While(
e2,
(Ast.Seq(s, (Ast.Exp e3, (get_pos e3))), get_pos s)),
pos))),
pos)
| Return (e) ->
revapp (compile_exp_r is e) [Jr(R31)]

(* compiles a Fish statement down to a list of MIPS instructions.
* Note that a "Return" is accomplished by placing the resulting
* value in R2 and then doing a Jr R31.
*)
let rec compile_stmt ((s,_):Ast.stmt) : inst list =
(*************************************************************)
raise IMPLEMENT_ME
(*************************************************************)
let compile_stmt (s :Ast.stmt) : inst list =
rev (compile_stmt_r [] s)

(* compiles Fish AST down to MIPS instructions and a list of global vars *)
let compile (p : Ast.program) : result =
let preoptimized = (constant_fold p) in
let _ = reset() in
let _ = collect_vars(p) in
let insts = (Label "main") :: (compile_stmt p) in
{ code = insts; data = VarSet.elements (!variables) }
let _ = collect_vars(preoptimized) in
let insts = (Label "main") :: (compile_stmt preoptimized) in
let optimized = (thread_jumps insts) in
{ code = optimized; data = VarSet.elements (!variables) }

let code_to_string code =
List.map (fun x -> (Mips.inst2string x) ^ "\n") code

(* converts the output of the compiler to a big string which can be
* dumped into a file, assembled, and run within the SPIM simulator
* (hopefully). *)
let result2string ({code;data}:result) : string =
let strs = List.map (fun x -> (Mips.inst2string x) ^ "\n") code in
let strs = code_to_string code in
let var2decl x = x ^ ":\t.word 0\n" in
"\t.text\n" ^
"\t.align\t2\n" ^
Expand Down
31 changes: 31 additions & 0 deletions ps2/compile_canned.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/sh

echo "[==========] Compiling Canned Fish Tests"

rm -rf compiled_tests

mkdir compiled_tests

if [[ -e ps2 ]]; then
for filename in `ls test/*.fish`; do
target=${filename%.fish}
output_file="compiled_tests/${target:5}.asm"

echo "\x1b\x5b1;36m[ COMPILE ]\x1b\x5b0m ${filename:5}"
# Tags on the debug print stuff at the header of the program so we can actually test
cat print.asm > $output_file
echo "\n" >> $output_file
# Compile
./ps2 $filename >> $output_file

# Tag on little bits to print out the results of the program
awk -v modified="${output_file%.asm}_test.asm" '{sub(/jr\t\$31/,"move $a0, $2\n\tj printInt");print > modified}' $output_file

# We don't need to keep the leftovers
rm $output_file
done
else
echo "\x1b\x5b1;31m[ ERROR ]\x1b\x5b0m: Compiler not found"
fi

echo "[==========] Complete"
Loading