1 (* Copyright (C) 2009-2010,2014 Matthew Fluet.
2 * Copyright (C) 1999-2008 Henry Cejtin, Matthew Fluet, Suresh
3 * Jagannathan, and Stephen Weeks.
4 * Copyright (C) 1997-2000 NEC Research Institute.
6 * MLton is released under a BSD-style license.
7 * See the file MLton-LICENSE for details.
10 functor amd64Codegen (S: AMD64_CODEGEN_STRUCTS): AMD64_CODEGEN =
14 structure amd64 = amd64 (open Machine
15 structure RepType = Type)
16 structure amd64Pseudo = amd64PseudoCheck (structure S = amd64)
18 structure amd64MLtonBasic
19 = amd64MLtonBasic (structure amd64 = amd64Pseudo
20 structure Machine = Machine)
22 structure amd64Liveness
23 = amd64Liveness (structure amd64 = amd64
24 structure amd64MLtonBasic = amd64MLtonBasic)
26 structure amd64JumpInfo
27 = amd64JumpInfo (structure amd64 = amd64)
29 structure amd64LoopInfo
30 = amd64LoopInfo (structure amd64 = amd64)
32 structure amd64EntryTransfer
33 = amd64EntryTransfer (structure amd64 = amd64)
36 = amd64MLton (structure amd64MLtonBasic = amd64MLtonBasic
37 structure amd64Liveness = amd64Liveness)
39 val implementsPrim = amd64MLton.implementsPrim
41 structure amd64Translate
42 = amd64Translate (structure amd64 = amd64
43 structure amd64MLton = amd64MLton
44 structure amd64Liveness = amd64Liveness)
46 structure amd64Simplify
47 = amd64Simplify (structure amd64 = amd64
48 structure amd64Liveness = amd64Liveness
49 structure amd64JumpInfo = amd64JumpInfo
50 structure amd64EntryTransfer = amd64EntryTransfer)
52 structure amd64GenerateTransfers
53 = amd64GenerateTransfers (structure amd64 = amd64
54 structure amd64MLton = amd64MLton
55 structure amd64Liveness = amd64Liveness
56 structure amd64JumpInfo = amd64JumpInfo
57 structure amd64LoopInfo = amd64LoopInfo
58 structure amd64EntryTransfer = amd64EntryTransfer)
60 structure amd64AllocateRegisters
61 = amd64AllocateRegisters (structure amd64 = amd64
62 structure amd64MLton = amd64MLton)
65 fun output {program as Machine.Program.T {chunks, frameLayouts, handlesSignals,
67 outputC: unit -> {file: File.t,
68 print: string -> unit,
70 outputS: unit -> {file: File.t,
71 print: string -> unit,
72 done: unit -> unit}}: unit
75 (* There is no sigaltstack on cygwin, we need to reserve %rsp to
76 * hold the C stack pointer. We only need to do this in programs
77 * that handle signals.
79 handlesSignals andalso let open Control.Target in !os = Cygwin end
84 val Machine.Program.T {profileInfo, ...} = program
87 NONE => Machine.ProfileInfo.empty
89 val {newProfileLabel, delProfileLabel, getProfileInfo} =
90 Machine.ProfileInfo.modify profileInfo
111 frameLayouts = frameLayouts,
112 frameOffsets = frameOffsets,
113 handlesSignals = handlesSignals,
115 maxFrameSize = maxFrameSize,
116 objectTypes = objectTypes,
117 profileInfo = SOME (getProfileInfo ()),
121 val {print, done, ...} = makeC ()
122 val additionalMainArgs =
124 val mainLabel = Label.toString (#label main)
125 (* Drop the leading _, because gcc will add it. *)
127 if !Control.labelsHaveExtra_
128 then String.dropPrefix (mainLabel, 1)
133 fun declareLocals () =
140 (chunks, ~1, fn (Machine.Chunk.T {regMax, ...}, max) =>
141 Int.max (max, regMax t))
144 print (concat ["PRIVATE ", CType.toString t,
145 " local", CType.toString t,
146 "[", Int.toString m, "];\n"])
151 CCodegen.outputDeclarations
152 {additionalMainArgs = additionalMainArgs,
153 includes = ["amd64-main.h"],
160 val outputC = Control.trace (Control.Pass, "outputC") outputC
162 (* Assembly specific *)
164 val _ = amd64MLtonBasic.init ()
166 fun outputJumpToSML print =
168 val win64 = case !Control.Target.os of
169 MLton.Platform.OS.Cygwin => true
170 | MLton.Platform.OS.MinGW => true
172 val jumpToSML = amd64.Label.fromString "MLton_jumpToSML"
173 val returnToC = amd64.Label.fromString "Thread_returnToC"
174 val {frontierReg, stackTopReg} =
175 {frontierReg = amd64.Register.r12,
176 stackTopReg = amd64.Register.rbp}
179 amd64.Assembly.pseudoop_text (),
180 amd64.Assembly.pseudoop_p2align
181 (amd64.Immediate.int 4, NONE, NONE),
182 amd64.Assembly.pseudoop_global jumpToSML,
183 amd64.Assembly.pseudoop_hidden jumpToSML,
184 amd64.Assembly.label jumpToSML,
185 amd64.Assembly.instruction_binal
186 {oper = amd64.Instruction.SUB,
187 src = amd64.Operand.immediate_int 72,
188 dst = amd64.Operand.register amd64.Register.rsp,
189 size = amd64.Size.QUAD},
190 amd64.Assembly.instruction_mov
191 {src = amd64.Operand.register amd64.Register.rbp,
192 dst = (amd64.Operand.address o amd64.Address.T)
193 {disp = SOME (amd64.Immediate.int 64),
194 base = SOME amd64.Register.rsp,
195 index= NONE, scale = NONE},
196 size = amd64.Size.QUAD},
197 amd64.Assembly.instruction_mov
198 {src = amd64.Operand.register amd64.Register.rbx,
199 dst = (amd64.Operand.address o amd64.Address.T)
200 {disp = SOME (amd64.Immediate.int 56),
201 base = SOME amd64.Register.rsp,
202 index= NONE, scale = NONE},
203 size = amd64.Size.QUAD},
204 amd64.Assembly.instruction_mov
205 {src = amd64.Operand.register amd64.Register.r12,
206 dst = (amd64.Operand.address o amd64.Address.T)
207 {disp = SOME (amd64.Immediate.int 48),
208 base = SOME amd64.Register.rsp,
209 index= NONE, scale = NONE},
210 size = amd64.Size.QUAD},
211 amd64.Assembly.instruction_mov
212 {src = amd64.Operand.register amd64.Register.r13,
213 dst = (amd64.Operand.address o amd64.Address.T)
214 {disp = SOME (amd64.Immediate.int 40),
215 base = SOME amd64.Register.rsp,
216 index= NONE, scale = NONE},
217 size = amd64.Size.QUAD},
218 amd64.Assembly.instruction_mov
219 {src = amd64.Operand.register amd64.Register.r14,
220 dst = (amd64.Operand.address o amd64.Address.T)
221 {disp = SOME (amd64.Immediate.int 32),
222 base = SOME amd64.Register.rsp,
223 index= NONE, scale = NONE},
224 size = amd64.Size.QUAD},
225 amd64.Assembly.instruction_mov
226 {src = amd64.Operand.register amd64.Register.r15,
227 dst = (amd64.Operand.address o amd64.Address.T)
228 {disp = SOME (amd64.Immediate.int 24),
229 base = SOME amd64.Register.rsp,
230 index= NONE, scale = NONE},
231 size = amd64.Size.QUAD},
232 amd64.Assembly.instruction_mov
233 {src = (amd64.Operand.address o amd64.Address.T)
234 {disp = SOME (amd64.Immediate.label amd64MLton.c_stackP),
235 base = SOME amd64.Register.rip, index = NONE, scale = NONE},
236 dst = amd64.Operand.register amd64.Register.rbx,
237 size = amd64.Size.QUAD},
238 amd64.Assembly.instruction_mov
239 {src = amd64.Operand.register amd64.Register.rbx,
240 dst = (amd64.Operand.address o amd64.Address.T)
241 {disp = SOME (amd64.Immediate.int 16),
242 base = SOME amd64.Register.rsp,
243 index = NONE, scale = NONE},
244 size = amd64.Size.QUAD},
245 amd64.Assembly.instruction_mov
246 {src = amd64.Operand.register amd64.Register.rsp,
247 dst = (amd64.Operand.address o amd64.Address.T)
248 {disp = SOME (amd64.Immediate.label amd64MLton.c_stackP),
249 base = SOME amd64.Register.rip, index = NONE, scale = NONE},
250 size = amd64.Size.QUAD},
251 amd64.Assembly.instruction_mov
252 {src = (amd64.Operand.address o amd64.Address.T)
253 {disp = (SOME o amd64.Immediate.labelPlusInt)
254 (amd64MLton.gcState_label,
256 (Machine.Runtime.GCField.offset
257 Machine.Runtime.GCField.StackTop)),
258 base = SOME amd64.Register.rip, index = NONE, scale = NONE},
259 dst = amd64.Operand.register stackTopReg,
260 size = amd64.Size.QUAD},
261 amd64.Assembly.instruction_mov
262 {src = (amd64.Operand.address o amd64.Address.T)
263 {disp = (SOME o amd64.Immediate.labelPlusInt)
264 (amd64MLton.gcState_label,
266 (Machine.Runtime.GCField.offset
267 Machine.Runtime.GCField.Frontier)),
268 base = SOME amd64.Register.rip, index = NONE, scale = NONE},
269 dst = amd64.Operand.register frontierReg,
270 size = amd64.Size.QUAD},
271 amd64.Assembly.instruction_jmp
272 {target = amd64.Operand.register
273 (if win64 then amd64.Register.rcx
274 else amd64.Register.rdi),
276 amd64.Assembly.pseudoop_p2align
277 (amd64.Immediate.int 4, NONE, NONE),
278 amd64.Assembly.pseudoop_global returnToC,
279 amd64.Assembly.pseudoop_hidden returnToC,
280 amd64.Assembly.label returnToC,
281 amd64.Assembly.instruction_mov
282 {src = (amd64.Operand.address o amd64.Address.T)
283 {disp = SOME (amd64.Immediate.label amd64MLton.c_stackP),
284 base = SOME amd64.Register.rip, index = NONE, scale = NONE},
285 dst = amd64.Operand.register amd64.Register.rsp,
286 size = amd64.Size.QUAD},
287 amd64.Assembly.instruction_mov
288 {src = (amd64.Operand.address o amd64.Address.T)
289 {disp = SOME (amd64.Immediate.int 16),
290 base = SOME amd64.Register.rsp,
291 index = NONE, scale = NONE},
292 dst = amd64.Operand.register amd64.Register.rbx,
293 size = amd64.Size.QUAD},
294 amd64.Assembly.instruction_mov
295 {src = amd64.Operand.register amd64.Register.rbx,
296 dst = (amd64.Operand.address o amd64.Address.T)
297 {disp = SOME (amd64.Immediate.label amd64MLton.c_stackP),
298 base = SOME amd64.Register.rip, index = NONE, scale = NONE},
299 size = amd64.Size.QUAD},
300 amd64.Assembly.instruction_mov
301 {src = (amd64.Operand.address o amd64.Address.T)
302 {disp = SOME (amd64.Immediate.int 24),
303 base = SOME amd64.Register.rsp,
304 index = NONE, scale = NONE},
305 dst = amd64.Operand.register amd64.Register.r15,
306 size = amd64.Size.QUAD},
307 amd64.Assembly.instruction_mov
308 {src = (amd64.Operand.address o amd64.Address.T)
309 {disp = SOME (amd64.Immediate.int 32),
310 base = SOME amd64.Register.rsp,
311 index = NONE, scale = NONE},
312 dst = amd64.Operand.register amd64.Register.r14,
313 size = amd64.Size.QUAD},
314 amd64.Assembly.instruction_mov
315 {src = (amd64.Operand.address o amd64.Address.T)
316 {disp = SOME (amd64.Immediate.int 40),
317 base = SOME amd64.Register.rsp,
318 index = NONE, scale = NONE},
319 dst = amd64.Operand.register amd64.Register.r13,
320 size = amd64.Size.QUAD},
321 amd64.Assembly.instruction_mov
322 {src = (amd64.Operand.address o amd64.Address.T)
323 {disp = SOME (amd64.Immediate.int 48),
324 base = SOME amd64.Register.rsp,
325 index = NONE, scale = NONE},
326 dst = amd64.Operand.register amd64.Register.r12,
327 size = amd64.Size.QUAD},
328 amd64.Assembly.instruction_mov
329 {src = (amd64.Operand.address o amd64.Address.T)
330 {disp = SOME (amd64.Immediate.int 56),
331 base = SOME amd64.Register.rsp,
332 index = NONE, scale = NONE},
333 dst = amd64.Operand.register amd64.Register.rbx,
334 size = amd64.Size.QUAD},
335 amd64.Assembly.instruction_mov
336 {src = (amd64.Operand.address o amd64.Address.T)
337 {disp = SOME (amd64.Immediate.int 64),
338 base = SOME amd64.Register.rsp,
339 index = NONE, scale = NONE},
340 dst = amd64.Operand.register amd64.Register.rbp,
341 size = amd64.Size.QUAD},
342 amd64.Assembly.instruction_binal
343 {oper = amd64.Instruction.ADD,
344 src = amd64.Operand.immediate_int 72,
345 dst = amd64.Operand.register amd64.Register.rsp,
346 size = amd64.Size.QUAD},
347 amd64.Assembly.instruction_ret {src = NONE}
352 fn asm => (Layout.print(Assembly.layout asm, print);
356 val liveInfo = amd64Liveness.LiveInfo.newLiveInfo ()
357 val jumpInfo = amd64JumpInfo.newJumpInfo ()
359 fun frameInfoToAMD64 (Machine.FrameInfo.T {frameLayoutsIndex, ...}) =
361 {frameLayoutsIndex = frameLayoutsIndex,
362 size = Bytes.toInt (#size (Vector.sub (frameLayouts,
363 frameLayoutsIndex)))}
365 fun outputChunk (chunk as Machine.Chunk.T {blocks, chunkLabel, ...},
369 = Machine.ChunkLabel.equals(#chunkLabel main, chunkLabel)
373 then outputJumpToSML print
377 = amd64Translate.translateChunk
379 frameInfoToAMD64 = frameInfoToAMD64,
382 val chunk : amd64.Chunk.t
383 = amd64Simplify.simplify
385 (* don't perform optimizations on
386 * the main function (initGlobals)
390 else !Control.Native.optimize,
391 delProfileLabel = delProfileLabel,
395 val unallocated_assembly : amd64.Assembly.t list list
396 = (amd64GenerateTransfers.generateTransfers
398 optimize = !Control.Native.optimize,
399 newProfileLabel = newProfileLabel,
402 reserveRsp = reserveRsp})
404 val allocated_assembly : Assembly.t list list
405 = amd64AllocateRegisters.allocateRegisters
406 {assembly = unallocated_assembly,
407 (* don't calculate liveness info
408 * on the main function (initGlobals)
410 liveness = not isMain}
412 val _ = Vector.foreach (blocks, Label.clear o Machine.Block.label)
413 val _ = amd64.Immediate.clearAll ()
414 val _ = amd64.MemLoc.clearAll ()
418 if isMain then 30 else 0,
424 => (Layout.print (Assembly.layout asm, print);
429 fun outputAssembly ()
431 val split = !Control.Native.split
434 val {print, done, ...} = makeS()
435 fun loop' (chunks, size)
441 | SOME maxSize => size > maxSize)
442 then (done (); loop (chunk::chunks))
444 size + outputChunk (chunk, print))
450 ; amd64Translate.translateChunk_totals ()
451 ; amd64Simplify.simplify_totals ()
452 ; amd64GenerateTransfers.generateTransfers_totals ()
453 ; amd64AllocateRegisters.allocateRegisters_totals ()
457 Control.trace (Control.Pass, "outputAssembly") outputAssembly