-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtigermain.sml
executable file
·276 lines (235 loc) · 9.13 KB
/
tigermain.sml
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
open tigerlex
open tigergrm
open tigerescap
open tigerseman
open BasicIO Nonstdio
fun lexstream(is: instream) =
Lexing.createLexer(fn b => fn n => buff_input is b 0 n);
fun errParsing(lbuf) = (print("Error en parsing!("
^(makestring(!num_linea))^
")["^(Lexing.getLexeme lbuf)^"]\n"); raise Fail "fin!")
fun main(args) =
let
fun arg(l, s) =
(List.exists (fn x => x=s) l, List.filter (fn x => x<>s) l)
(* OPTIONS *)
val (arbol, l1) = arg(args, "-arbol")
val (escapes, l2) = arg(l1, "-escapes")
val (ir, l3) = arg(l2, "-ir")
val (canon, l4) = arg(l3, "-canon")
val (code, l5) = arg(l4, "-code")
val (flow, l6) = arg(l5, "-flow")
val (inter, l7) = arg(l6, "-inter")
val (debug, l8) = arg(l7, "-debug")
val (liveout, l9) = arg(l8, "-liveout")
val (color, l10) = arg(l9, "-color")
val (assembly, l11) = arg(l10, "-assembly")
val (entrada, fileName) =
case l11 of (* Remember to change this value in case of new options *)
[n] => ((open_in n, n)
handle _ => raise Fail (n^" no existe"))
| [] => (std_in, "")
| _ => raise Fail "opción desconocida"
val lexbuf = lexstream entrada
val expr = prog Tok lexbuf handle _ => errParsing lexbuf (* AST, with escapes *)
val _ = findEscape(expr) (* AST, without escapes *)
(* -arbol OPTION *)
val _ = if arbol
then
tigerpp.exprAst expr
else
()
(* Evaluate input expression: type-checking, and translation to IR code *)
val _ = transProg(expr);
(* Canonize function *)
(* canonize : tigertree.stm -> tigertree.stm list *)
val canonize = tigercanon.traceSchedule
o tigercanon.basicBlocks
o tigercanon.linearize
val fragments = tigertrans.getResult()
(* -ir OPTION *)
val _ = if ir
then
print(tigertrans.Ir(fragments))
else
()
fun fragPartition [] (procs, strings) = (List.rev procs, List.rev strings)
| fragPartition (tigerframe.PROC p :: fl) (procs, strings) = fragPartition fl (p :: procs, strings)
| fragPartition (tigerframe.STRING s :: fl) (procs, strings) = fragPartition fl (procs, s :: strings)
(* procs : tigerframe.frag list - PROC;
strings : tigerframe.frag list - STRING *)
val (procs, strings) : ({body : tigertree.stm, frame : tigerframe.frame} list * (tigertemp.label * string) list) = fragPartition fragments ([], [])
val canonProcs : (tigertree.stm list * tigerframe.frame) list = List.map (fn {body, frame} =>
(canonize body, frame)) procs
(* -canon OPTION *)
val _ = if canon
then
List.app (fn (c, f) =>
(print("\n"^tigerframe.name(f)^":\n");
List.app (print o tigerit.tree) c)) canonProcs (* c : tigertree.stm list *)
else
()
(* -inter OPTION *)
val _ = if inter
then
tigerinterp.inter debug canonProcs strings
else
()
val assem : (tigerassem.instr list * tigerframe.frame) list = List.map (fn (cbody, frame) =>
let
val instrList = List.concat (List.map (tigercodegen.codegen frame) cbody) (* cbody is a tigertree.stm list;
tigercodegen.codegen returns a instr list. Then, we have to flat a list of lists *)
val instrList' = tigerframe.procEntryExit2(frame, instrList) (* Apply tigerframe.procEntryExit2() *)
in
(instrList', frame)
end) canonProcs
(* Format, using tigertemp.makeString, each instruction converted to assembly language *)
fun assemToString (assem : (tigerassem.instr list * tigerframe.frame) list) : (tigertemp.label * string list) list =
List.map (fn (ilist, frame) =>
(tigerframe.name frame, List.map (tigerassem.format tigertemp.makeString) ilist)) assem
(* -code OPTION *)
val _ = if code
then
List.app (fn (fName, instrStrList) =>
(print("\n"^fName^":\n\n");
List.app print instrStrList)) (assemToString assem)
else
()
(* LIVENESS ANALYSIS *)
fun prepareLiveOutInfo() =
let
val liveOutInfo : (string * (string * string * string * string) list) list = List.map (fn (instrList, frame) =>
let
val info = tigerliveness.liveOutInfoToString instrList
val fName = tigerframe.name frame
in
(fName, info)
end) assem
(* Concat live-out info in one string *)
val liveOutInfo' : (string * string list) list = List.map (fn (fName, liveOutInfoToStringList) =>
(fName, List.map (fn (instrStr, nStr, succSetStr, liveOutStr) =>
let
val concatValues = "("^instrStr^";\tnode = "^nStr^";\tsuccs = "^succSetStr^";\tlive-out = "^liveOutStr^")\n"
in
concatValues
end) liveOutInfoToStringList)) liveOutInfo
in
liveOutInfo'
end
(* -liveout OPTION *)
val _ = if liveout
then
List.app (fn (fName, liveOutInfoToStringList) =>
(print("\n"^fName^":\t(instr list length = "^Int.toString (List.length liveOutInfoToStringList)^")\n\n");
List.app print liveOutInfoToStringList)) (prepareLiveOutInfo())
else
()
(* REGISTER ALLOCATION *)
(* computeRegisterAllocation : (tigerassem.instr list * tigerframe.frame) list -> (string list * tigerframe.frame) list *)
fun computeRegisterAllocation (procList : (tigerassem.instr list * tigerframe.frame) list) : (string list * tigerframe.frame) list =
let
(* Compute register allocation per function *)
val regAlloc : ((tigerregalloc.allocation * tigerassem.instr list) * tigerframe.frame) list = List.map (fn (instrList, frame) =>
(tigerregalloc.regAlloc (instrList, frame), frame)) procList
fun coloring (dict : tigerregalloc.allocation) (instrList : tigerassem.instr list) : string list =
let
fun sayTemp (str : string) : tigertemp.temp =
let
val color = case Splaymap.peek(dict, str) of
SOME c => c
| NONE => let
val _ = print("\nKey not found in allocation = "^str^"\n")
in
raise Fail "Error - main. computeRegisterAllocation(). coloring(): peek error"
end
in
color
end
in
List.map (tigerassem.format sayTemp) instrList
end
(* Replace each temporary with it's corresponding color (machine register) computed *)
val replace : (string list * tigerframe.frame) list = List.map (fn ((colorDic, instrList), frame) =>
(coloring colorDic instrList, frame)) regAlloc
in
replace
end
(* -color OPTION *)
val _ = if color
then
List.app (fn (instrListStr, frame) =>
(print("\n"^tigerframe.name frame^" (instruction list length = "^Int.toString (List.length instrListStr)^"):\n\n");
List.app print instrListStr)) (computeRegisterAllocation assem)
else
()
(* Returns a string containing entire program in assembly-lang *)
(* createFinalOutputAssembly : (string list * tigerframe.frame) list -> (tigertemp.label * string) list -> string *)
fun createFinalOutputAssembly (procs : (string list * tigerframe.frame) list) (strings : (tigertemp.label * string) list) : string =
let
(* prepareProcs : (string list * tigerframe.frame) list *)
fun prepareProcs procs =
let
(* Prepend a \t to each assembly instruction *)
val procs' : (string list * tigerframe.frame) list = List.map (fn (strList, frame) =>
(List.map (fn str =>
"\t"^str) strList, frame)) procs
(* Assembly code now in just one string *)
val procs'' : (string * tigerframe.frame) list = List.map (fn (strList, frame) =>
(String.concat strList, frame)) procs'
in
procs''
end
(* convertStringFragsToString : unit -> string *)
fun convertStringFragsToString() : string =
let
val mapped : string list = List.map (fn (label, str) =>
tigerframe.string(label, str)) strings
in
String.concat mapped
end
val procs' : (string * tigerframe.frame) list = prepareProcs procs
(* Apply tigerframe.procEntryExit3() to each function on procs', and returns the strings' compilation
in just one string *)
fun appProcEntryExit3() : string =
let
val mapped = List.map (fn (body, frame) =>
tigerframe.procEntryExit3 frame body) procs'
in
String.concat mapped
end
in
String.concat [
"### Program assembly. x64 architecture; AT&T syntax\n\n",
".file\t \""^fileName^"\""^"\n\n",
".data\n",
convertStringFragsToString()^"\n",
".text"^"\n",
".globl _tigermain"^"\n",
appProcEntryExit3()
]
end
val finalOutputAssembly : string = createFinalOutputAssembly (computeRegisterAllocation assem) strings
(* -assem OPTION *)
val _ = if assembly
then
print("\n**********\tFINAL OUTPUT ASSEMBLY\t**********\n\n"^finalOutputAssembly^"\n")
else
()
(* Write final program assembly into a file *)
val _ = if fileName <> ""
then
let
val out = TextIO.openOut("result.s")
in
TextIO.output(out, finalOutputAssembly);
TextIO.closeOut(out)
end
else
()
(* Execute GCC, and run the input program *)
val _ = Process.system("gcc -g -c runtime.c && gcc -g result.s runtime.o -o result.bin && ./result.bin")
in
print("\nSuccessful compilation. Errors not found.\n")
end
handle Fail s => print("Fail: "^s^"\n")
val _ = main(CommandLine.arguments())