forked from reactorlabs/sourir
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sourir.ml
161 lines (147 loc) · 5.27 KB
/
sourir.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
open Instr
let run = ref true
let quiet = ref false
let autofix = ref false
let opts = ref []
let path = ref ""
let ott = ref false
let num_opts = ref 1
let llvm = ref false
let no_optimize = ref false
let () =
let cmd_args = [
("--run", Arg.Set run, "run the program (default)");
("--no-run", Arg.Clear run, "do not run the program, just show the optimized source code");
("--quiet", Arg.Set quiet, "quiet");
("--autofix", Arg.Set autofix, "automatically normalize graph");
("--opt", Arg.String (fun s -> opts := String.split_on_char ',' s), "Enable optimizations");
("--num", Arg.String (fun s -> num_opts := int_of_string s), "Number of optimization runs");
("--ott", Arg.Set ott, "Output ott rendering");
("--llvm", Arg.Set llvm, "Append LLVM output");
("--no-optimize", Arg.Set no_optimize, "Don't optimize (for debugging)");
] in
Arg.parse cmd_args (fun s ->
if !path <> "" then raise (Arg.Bad ("Invalid argument "^s));
path := s) "options";
if !path = "" then (
Printf.eprintf
"You should provide a Sourir file to parse as command-line argument.\n\
Example: %s examples/sum.sou\n%!"
Sys.executable_name;
exit 1);
let program =
try Parse.program_of_file !path
with Parse.Error error ->
Parse.report_error error;
exit 2
in
let program =
if !autofix
then Transform.try_opt Transform.normalize_graph program
else program in
opts := if !opts = ["all"] then Transform.all_opts else !opts;
let check_prog program =
begin try Check.well_formed program with
| Check.MissingMain ->
Printf.eprintf "Program is missing an explicit or implicit main function\n";
exit 1
| Check.InvalidMain ->
Printf.eprintf "Main function cannot have arguments\n";
exit 1
| Check.DuplicateFunctionDeclaration f ->
Printf.eprintf "Duplicate function declaration %s\n" f;
exit 1
| Check.DuplicateVersion (f, v) ->
Printf.eprintf "Version %s in function %s is defined twice\n" v f;
exit 1
| Check.EmptyFunction f ->
Printf.eprintf "Function %s has no body\n" f;
exit 1
| Check.DuplicateParameter (f, x) ->
Printf.eprintf "Function %s : parameter %s is given twice\n" f x;
exit 1
| Check.ErrorAt (f, v, e) ->
Printf.eprintf "Error in function %s version %s: " f v;
begin match[@warning "-4"] e with
| Check.MissingReturn ->
Printf.eprintf "missing return statement\n";
| Check.FunctionDoesNotExist f' ->
Printf.eprintf "called function %s does not exist\n" f';
| Check.VersionDoesNotExist (f', v') ->
Printf.eprintf "bailout target %s %s does not exist\n" f' v';
| Check.InvalidNumArgs pc ->
Printf.eprintf "at line %d: invalid number of arguments\n" (pc+1);
| Check.InvalidArgument (pc, expression) ->
Printf.eprintf "at line %d: invalid argument\n" (pc+1);
| Instr.Unbound_label (MergeLabel l) ->
Printf.eprintf "label %s does not exist\n" l;
| Instr.Unbound_label (BranchLabel l) ->
Printf.eprintf "label $%s does not exist\n" l;
| Instr.Unbound_bailout_label l ->
Printf.eprintf "bailout target %s does not exist\n" l;
| Check.BranchLabelReused pc ->
Printf.eprintf "label at line %d is used more than once\n" (pc+1);
| Check.FallthroughLabel pc ->
Printf.eprintf "fallthrough label at line %d is not allowed\n" (pc+1);
| Check.EntryPointIsLabel ->
Printf.eprintf "the first instruction cannot be a label\n";
| Check.DuplicateLabel l ->
Printf.eprintf "label %s used multiple times\n" l;
| _ -> assert(false)
end;
exit 1
end
in
check_prog program;
begin try Scope.check_program program with
| Scope.ScopeExceptionAt _ as exn ->
Printf.eprintf "Scope error in the source program:\n";
Scope.report_error program exn
end;
let optimize program =
let optimizations = Transform.optimize !opts !num_opts in
Transform.(try_opt optimizations program)
in
let program =
if not !no_optimize
then try optimize program with
| Transform.UnknownOptimization opt ->
Printf.eprintf "Unknown optimization %s.\nValid optimizers are %s\n"
opt (String.concat ", " (Transform.all_opts @ Transform.manual_opts));
exit 1
else program
in
if !ott then begin
Ott.disassemble_o stdout program;
exit 0
end;
if not !quiet then begin
Printf.printf "After optimizations\n";
Disasm.disassemble_o stdout program
end;
check_prog program;
begin try Scope.check_program program with
| Scope.ScopeExceptionAt _ as exn ->
Printf.eprintf "Scope error in the optimized program (%s):\n"
(String.concat ", " !opts);
Scope.report_error program exn
end;
(* Try running the program though llvm before optimizing *)
if !llvm then begin
let the_module = Codegen.generate program in
let _ = Jit.exec the_module in ()
end else begin
if not !run then ()
else begin
let conf = Eval.run_interactive IO.stdin_input program in
let open Eval in
match conf.status with
| Running -> assert(false)
| Result (Int n) ->
exit n
| Result (Bool b) ->
exit (if b then 1 else 0)
| Result (Fun_ref _ | Array _ | Nil) ->
exit 0
end
end