SCM Repository
Annotation of /sml/trunk/src/MLRISC/ppc/c-calls/ppc-macosx.sml
Parent Directory
|
Revision Log
Revision 1443 - (view) (download)
1 : | jhr | 1346 | (* ppc-macosx.sml |
2 : | * | ||
3 : | * COPYRIGHT (c) 2003 John Reppy (http://www.cs.uchicago.edu/~jhr) | ||
4 : | * All rights reserved. | ||
5 : | * | ||
6 : | * C function calls for the PowerPC using the MacOS X ABI. | ||
7 : | * | ||
8 : | * Register conventions: | ||
9 : | * | ||
10 : | * Register Callee-save Purpose | ||
11 : | * -------- ----------- ------- | ||
12 : | * GPR0 no Zero | ||
13 : | * 1 no Stack pointer | ||
14 : | * 2 no scratch (TOC on AIX) | ||
15 : | * 3 no arg0 and return result | ||
16 : | * 4-10 no arg1-arg7 | ||
17 : | * 11 no scratch | ||
18 : | * 12 no holds taget of indirect call | ||
19 : | * 13-31 yes callee-save registers | ||
20 : | * | ||
21 : | * FPR0 no scratch | ||
22 : | * 1-13 no floating-point arguments | ||
23 : | * 14-31 yes floating-point callee-save registers | ||
24 : | * | ||
25 : | * V0-V1 no scratch vector registers | ||
26 : | * 2-13 no vector argument registers | ||
27 : | * 14-19 no scratch vector registers | ||
28 : | * 20-31 yes callee-save vector registers | ||
29 : | * | ||
30 : | * LR no link register holds return address | ||
31 : | * | ||
32 : | * CR0-CR1 no scratch condition registers | ||
33 : | * 2-4 yes callee-save condition registers | ||
34 : | * 5-7 no scratch condition registers | ||
35 : | * | ||
36 : | * Calling convention: | ||
37 : | * | ||
38 : | * Return result: | ||
39 : | * + Integer and pointer results are returned in GPR3 | ||
40 : | * + 64-bit integers (long long) returned in GPR3/GPR4 | ||
41 : | * + float/double results are returned in FPR1 | ||
42 : | * + Struct results are returned in space provided by the caller. | ||
43 : | * The address of this space is passed to the callee as an | ||
44 : | * implicit first argument in GPR3 and the first real argument is | ||
45 : | * passed in GPR4. | ||
46 : | * | ||
47 : | * Function arguments: | ||
48 : | * * arguments (except for floating-point values) are passed in | ||
49 : | * registers GPR3-GPR10 | ||
50 : | jhr | 1438 | * |
51 : | * Note also that stack frames are supposed to be 16-byte aligned. | ||
52 : | jhr | 1346 | *) |
53 : | |||
54 : | (* we extend the interface to support generating the stubs needed for | ||
55 : | * dynamic linking (see "Inside MacOS X: Mach-O Runtime Architecture" | ||
56 : | * for details. | ||
57 : | *) | ||
58 : | signature PPC_MACOSX_C_CALLS = | ||
59 : | sig | ||
60 : | include C_CALLS | ||
61 : | jhr | 1438 | |
62 : | (* | ||
63 : | val genStub : { | ||
64 : | name : T.rexp, | ||
65 : | proto : CTypes.c_proto, | ||
66 : | paramAlloc : {szb : int, align : int} -> bool, | ||
67 : | structRet : {szb : int, align : int} -> T.rexp, | ||
68 : | saveRestoreDedicated : | ||
69 : | T.mlrisc list -> {save: T.stm list, restore: T.stm list}, | ||
70 : | callComment : string option, | ||
71 : | args : c_arg list | ||
72 : | } -> { | ||
73 : | callseq : T.stm list, | ||
74 : | result: T.mlrisc list | ||
75 : | } | ||
76 : | *) | ||
77 : | |||
78 : | jhr | 1346 | end; |
79 : | |||
80 : | functor PPCMacOSX_CCalls ( | ||
81 : | |||
82 : | structure T : MLTREE | ||
83 : | val ix : (T.stm, T.rexp, T.fexp, T.ccexp) PPCInstrExt.sext -> T.sext | ||
84 : | |||
85 : | ): PPC_MACOSX_C_CALLS = struct | ||
86 : | structure T = T | ||
87 : | structure Ty = CTypes | ||
88 : | structure C = PPCCells | ||
89 : | structure IX = PPCInstrExt | ||
90 : | |||
91 : | fun error msg = MLRiscErrorMsg.error ("PPCCompCCalls", msg) | ||
92 : | |||
93 : | datatype arg_loc | ||
94 : | = GPR of C.cell | ||
95 : | | FPR of C.cell | ||
96 : | | STK | ||
97 : | |||
98 : | type arg_pos = { | ||
99 : | offset : int, (* stack offset of memory for argument *) | ||
100 : | loc : arg_loc (* location where argument is passed *) | ||
101 : | } | ||
102 : | |||
103 : | datatype c_arg | ||
104 : | = ARG of T.rexp | ||
105 : | | FARG of T.fexp | ||
106 : | | ARGS of c_arg list | ||
107 : | |||
108 : | val mem = T.Region.memory | ||
109 : | val stack = T.Region.memory | ||
110 : | |||
111 : | val maxRegArgs = 6 | ||
112 : | val paramAreaOffset = 68 | ||
113 : | |||
114 : | jhr | 1443 | fun LI i = T.LI(T.I.fromInt (32, i)) |
115 : | jhr | 1346 | |
116 : | jhr | 1443 | fun reg r = C.GPReg r |
117 : | fun freg r = C.FPReg r | ||
118 : | jhr | 1346 | |
119 : | jhr | 1443 | fun reg32 r = T.REG(32, r) |
120 : | fun freg64 r = T.FREG(64, r) | ||
121 : | jhr | 1346 | |
122 : | jhr | 1443 | (* stack pointer *) |
123 : | val sp = reg1 | ||
124 : | val spR = reg32 sp | ||
125 : | jhr | 1346 | |
126 : | fun addli (x, 0) = x | ||
127 : | | addli (x, d) = let | ||
128 : | jhr | 1438 | val d' = T.I.fromInt (32, d) |
129 : | in | ||
130 : | case x | ||
131 : | of T.ADD (_, r, T.LI d) => | ||
132 : | T.ADD (32, r, T.LI (T.I.ADD (32, d, d'))) | ||
133 : | jhr | 1346 | | _ => T.ADD (32, x, T.LI d') |
134 : | jhr | 1443 | (* end case *) |
135 : | jhr | 1438 | end |
136 : | jhr | 1346 | |
137 : | fun argaddr n = addli (spreg, paramAreaOffset + 4*n) | ||
138 : | |||
139 : | jhr | 1443 | (* layout information for C types; note that stack and struct alignment |
140 : | * are different for some types | ||
141 : | *) | ||
142 : | type layout_info = { | ||
143 : | sz : int, | ||
144 : | stkAlign : int, | ||
145 : | structAlign : int | ||
146 : | } | ||
147 : | jhr | 1346 | |
148 : | fun roundup (i, a) = a * ((i + a - 1) div a) | ||
149 : | |||
150 : | jhr | 1443 | (* layout information for integer types *) |
151 : | local | ||
152 : | fun layout n = {sz = n, stkAlign = n, structAlign = n} | ||
153 : | jhr | 1438 | |
154 : | jhr | 1443 | fun intSizeAndAlign Ty.I_char = layout 1 |
155 : | | intSizeAndAlign Ty.I_short = layout 2 | ||
156 : | | intSizeAndAlign Ty.I_int = layout 4 | ||
157 : | | intSizeAndAlign Ty.I_long = layout 4 | ||
158 : | | intSizeAndAlign Ty.I_long_long = {sz = 8, stkAlign = 8, structAlign = 4} | ||
159 : | |||
160 : | in | ||
161 : | |||
162 : | jhr | 1438 | (* calculate size and alignment for a C type *) |
163 : | fun szal (T.C_unsigned ty) = intSizeAndAlign ty | ||
164 : | | szal (T.C_signed ty) = intSizeAndAlign ty | ||
165 : | | szal Ty.C_void = raise Fail "unexpected void type" | ||
166 : | jhr | 1443 | | szal Ty.C_float = layout 4 |
167 : | | szal Ty.C_PTR = layout 4 | ||
168 : | | szal Ty.C_double = {sz = 8, stkAlign = 8, structAlign = 4} | ||
169 : | | szal (Ty.C_long_double) = {sz = 8, stkAlign = 8, structAlign = 4} | ||
170 : | | szal (Ty.C_ARRAY(t, n)) = let | ||
171 : | val a = szal t | ||
172 : | in | ||
173 : | {sz = n * #sz a, stkAlign = ?, structAlign = #structAlign a} | ||
174 : | end | ||
175 : | jhr | 1438 | | szal (Ty.C_STRUCT l) = let |
176 : | (* FIXME: the rules for structs are more complicated (and they also depend | ||
177 : | * on the alignment mode). In Power alignment, 8-byte quantites like | ||
178 : | * long long and double are 4-byte aligned in structs. | ||
179 : | *) | ||
180 : | (* i: next free memory address (relative to struct start); | ||
181 : | * a: current total alignment, | ||
182 : | * l: list of struct member types | ||
183 : | *) | ||
184 : | fun pack (i, a, []) = | ||
185 : | (* when we are done with all elements, the total size | ||
186 : | * of the struct must be padded out to its own alignment | ||
187 : | *) | ||
188 : | jhr | 1346 | (roundup (i, a), a) |
189 : | jhr | 1438 | | pack (i, a, t :: tl) = let |
190 : | val (ts, ta) = szal t (* size and alignment for member *) | ||
191 : | jhr | 1346 | in |
192 : | jhr | 1438 | (* member must be aligned according to its own |
193 : | * alignment requirement; the next free position | ||
194 : | * is then at "aligned member-address plus member-size"; | ||
195 : | * new total alignment is max of current alignment | ||
196 : | * and member alignment (assuming all alignments are | ||
197 : | * powers of 2) *) | ||
198 : | pack (roundup (i, ta) + ts, Int.max (a, ta), tl) | ||
199 : | jhr | 1346 | end |
200 : | jhr | 1438 | in |
201 : | jhr | 1346 | pack (0, 1, l) |
202 : | jhr | 1438 | end |
203 : | jhr | 1443 | end |
204 : | jhr | 1346 | |
205 : | jhr | 1443 | datatype arg |
206 : | = Simple of (Ty.c_type * arg_pos) (* includes arrays *) | ||
207 : | | Struct of arg list | ||
208 : | |||
209 : | (* layout arguments *) | ||
210 : | fun layout argTys = let | ||
211 : | fun assign ([], _, _, offset, args) = (offset, List.rev args) | ||
212 : | | assign (x::xs, gprs, fprs, offset, args) = let | ||
213 : | fun assignInt sz = (case (sz, gprs) | ||
214 : | of (_, []) => | ||
215 : | assign(xs, [], fprs, | ||
216 : | | (8, [r]) => | ||
217 : | | (8, r1::r2::rs) => | ||
218 : | | (_, r::rs) => | ||
219 : | (* end case *)) | ||
220 : | in | ||
221 : | case x | ||
222 : | of (Ty.C_unsigned _) => assignInt x | ||
223 : | | (Ty.C_signed _) => assignInt x | ||
224 : | | (Ty.C_PTR) => assignInt x | ||
225 : | | (Ty.C_float) => assignFlt x | ||
226 : | | (Ty.C_double) => assignFlt x | ||
227 : | | (Ty.C_long_double) => assignFlt x | ||
228 : | | (Ty.C_ARRAY(ty, n)) => | ||
229 : | | (Ty.CSTRUCT tys) => | ||
230 : | (* end case *) | ||
231 : | end | ||
232 : | in | ||
233 : | end | ||
234 : | |||
235 : | jhr | 1346 | fun genCall { name, proto, paramAlloc, structRet, saveRestoreDedicated, |
236 : | callComment, args } = let | ||
237 : | val { conv, retTy, paramTys } = proto | ||
238 : | val _ = case conv of | ||
239 : | ("" | "ccall") => () | ||
240 : | | _ => error (concat ["unknown calling convention \"", | ||
241 : | String.toString conv, "\""]) | ||
242 : | val res_szal = | ||
243 : | case retTy of | ||
244 : | (Ty.C_long_double | Ty.C_STRUCT _) => SOME (szal retTy) | ||
245 : | | _ => NONE | ||
246 : | |||
247 : | val nargwords = let | ||
248 : | fun loop ([], n) = n | ||
249 : | | loop (t :: tl, n) = | ||
250 : | loop (tl, (case t of | ||
251 : | (Ty.C_double | Ty.C_signed Ty.I_long_long | | ||
252 : | Ty.C_unsigned Ty.I_long_long) => 2 | ||
253 : | | _ => 1) + n) | ||
254 : | in | ||
255 : | loop (paramTys, 0) | ||
256 : | end | ||
257 : | |||
258 : | val regargwords = Int.min (nargwords, maxRegArgs) | ||
259 : | val stackargwords = Int.max (nargwords, maxRegArgs) - maxRegArgs | ||
260 : | |||
261 : | val stackargsstart = paramAreaOffset + 4 * maxRegArgs | ||
262 : | |||
263 : | val scratchstart = stackargsstart + 4 * stackargwords | ||
264 : | |||
265 : | (* Copy struct or part thereof to designated area on the stack. | ||
266 : | * An already properly aligned address (relative to %sp) is | ||
267 : | * in to_off. *) | ||
268 : | fun struct_copy (sz, al, ARG a, t, to_off, cpc) = | ||
269 : | (* Two main cases here: | ||
270 : | * 1. t is C_STRUCT _: in this case "a" computes the address | ||
271 : | * of the struct to be copied. | ||
272 : | * 2. t is some other non-floating type; "a" computes the | ||
273 : | * the corresponding value (i.e., not its address). | ||
274 : | *) | ||
275 : | let fun ldst ty = | ||
276 : | T.STORE (ty, addli (spreg, to_off), a, stack) :: cpc | ||
277 : | in | ||
278 : | case t of | ||
279 : | (Ty.C_void | Ty.C_PTR | | ||
280 : | Ty.C_signed (Ty.I_int | Ty.I_long) | | ||
281 : | Ty.C_unsigned (Ty.I_int | Ty.I_long)) => ldst 32 | ||
282 : | | (Ty.C_signed Ty.I_char | Ty.C_unsigned Ty.I_char) => ldst 8 | ||
283 : | | (Ty.C_signed Ty.I_short | Ty.C_unsigned Ty.I_short) => | ||
284 : | ldst 16 | ||
285 : | | (Ty.C_signed Ty.I_long_long | | ||
286 : | Ty.C_unsigned Ty.I_long_long) => ldst 64 | ||
287 : | | (Ty.C_ARRAY _) => | ||
288 : | error "ARRAY within gather/scatter struct" | ||
289 : | | (Ty.C_STRUCT _) => | ||
290 : | (* Here we have to do the equivalent of a "memcpy". *) | ||
291 : | let val from = a (* argument is address of struct *) | ||
292 : | fun cp (ty, incr) = let | ||
293 : | fun load_from from_off = | ||
294 : | T.LOAD (32, addli (from, from_off), mem) | ||
295 : | (* from_off is relative to from, | ||
296 : | * to_off is relative to %sp *) | ||
297 : | fun loop (i, from_off, to_off, cpc) = | ||
298 : | if i <= 0 then cpc | ||
299 : | else loop (i - incr, | ||
300 : | from_off + incr, to_off + incr, | ||
301 : | T.STORE (ty, addli (spreg, to_off), | ||
302 : | load_from from_off, | ||
303 : | stack) | ||
304 : | :: cpc) | ||
305 : | in | ||
306 : | loop (sz, 0, to_off, cpc) | ||
307 : | end | ||
308 : | in | ||
309 : | case al of | ||
310 : | 1 => cp (8, 1) | ||
311 : | | 2 => cp (16, 2) | ||
312 : | | _ => (* 4 or more *) cp (32, 4) | ||
313 : | end | ||
314 : | | (Ty.C_float | Ty.C_double | Ty.C_long_double) => | ||
315 : | error "floating point type does not match ARG" | ||
316 : | end | ||
317 : | | struct_copy (_, _, ARGS args, Ty.C_STRUCT tl, to_off, cpc) = | ||
318 : | (* gather/scatter case *) | ||
319 : | let fun loop ([], [], _, cpc) = cpc | ||
320 : | | loop (t :: tl, a :: al, to_off, cpc) = let | ||
321 : | val (tsz, tal) = szal t | ||
322 : | val to_off' = roundup (to_off, tal) | ||
323 : | val cpc' = struct_copy (tsz, tal, a, t, to_off', cpc) | ||
324 : | in | ||
325 : | loop (tl, al, to_off' + tsz, cpc') | ||
326 : | end | ||
327 : | | loop _ = | ||
328 : | error "number of types does not match number of arguments" | ||
329 : | in | ||
330 : | loop (tl, args, to_off, cpc) | ||
331 : | end | ||
332 : | | struct_copy (_, _, ARGS _, _, _, _) = | ||
333 : | error "gather/scatter for non-struct" | ||
334 : | | struct_copy (sz, al, FARG a, t, to_off, cpc) = | ||
335 : | let fun fldst ty = | ||
336 : | T.FSTORE (ty, addli (spreg, to_off), a, stack) :: cpc | ||
337 : | in | ||
338 : | case t of | ||
339 : | Ty.C_float => fldst 32 | ||
340 : | | Ty.C_double => fldst 64 | ||
341 : | | Ty.C_long_double => fldst 128 | ||
342 : | | _ => error "non-floating-point type does not match FARG" | ||
343 : | end | ||
344 : | |||
345 : | val (stackdelta, argsetupcode, copycode) = let | ||
346 : | fun loop ([], [], _, ss, asc, cpc) = | ||
347 : | (roundup (Int.max (0, ss - stackargsstart), 8), asc, cpc) | ||
348 : | | loop (t :: tl, a :: al, n, ss, asc, cpc) = let | ||
349 : | fun wordassign a = | ||
350 : | if n < 6 then T.MV (32, oreg n, a) | ||
351 : | else T.STORE (32, argaddr n, a, stack) | ||
352 : | fun wordarg (a, cpc, ss) = | ||
353 : | loop (tl, al, n + 1, ss, wordassign a :: asc, cpc) | ||
354 : | |||
355 : | fun dwordmemarg (addr, region, tmpstore) = let | ||
356 : | fun toreg (n, addr) = | ||
357 : | T.MV (32, oreg n, T.LOAD (32, addr, region)) | ||
358 : | fun tomem (n, addr) = | ||
359 : | T.STORE (32, | ||
360 : | argaddr n, | ||
361 : | T.LOAD (32, addr, region), | ||
362 : | stack) | ||
363 : | fun toany (n, addr) = | ||
364 : | if n < 6 then toreg (n, addr) else tomem (n, addr) | ||
365 : | in | ||
366 : | (* if n < 6 andalso n div 2 = 0 then | ||
367 : | * use ldd here once MLRISC gets its usage right | ||
368 : | * else | ||
369 : | * ... *) | ||
370 : | loop (tl, al, n+2, ss, | ||
371 : | tmpstore @ | ||
372 : | toany (n, addr) | ||
373 : | :: toany (n+1, addli (addr, 4)) | ||
374 : | :: asc, | ||
375 : | cpc) | ||
376 : | end | ||
377 : | fun dwordarg mkstore = | ||
378 : | if n > 6 andalso n div 2 = 1 then | ||
379 : | (* 8-byte aligned memory *) | ||
380 : | loop (tl, al, n+2, ss, | ||
381 : | mkstore (argaddr n) :: asc, | ||
382 : | cpc) | ||
383 : | else dwordmemarg (tmpaddr, stack, [mkstore tmpaddr]) | ||
384 : | in | ||
385 : | case (t, a) of | ||
386 : | ((Ty.C_void | Ty.C_PTR | Ty.C_ARRAY _ | | ||
387 : | Ty.C_unsigned (Ty.I_int | Ty.I_long) | | ||
388 : | Ty.C_signed (Ty.I_int | Ty.I_long)), | ||
389 : | ARG a) => wordarg (a, cpc, ss) | ||
390 : | | (Ty.C_signed Ty.I_char, ARG a) => | ||
391 : | wordarg (T.SX (32, 8, a), cpc, ss) | ||
392 : | | (Ty.C_unsigned Ty.I_char, ARG a) => | ||
393 : | wordarg (T.ZX (32, 8, a), cpc, ss) | ||
394 : | | (Ty.C_signed Ty.I_short, ARG a) => | ||
395 : | wordarg (T.SX (32, 16, a), cpc, ss) | ||
396 : | | (Ty.C_unsigned Ty.I_short, ARG a) => | ||
397 : | wordarg (T.ZX (32, 16, a), cpc, ss) | ||
398 : | | ((Ty.C_signed Ty.I_long_long | | ||
399 : | Ty.C_unsigned Ty.I_long_long), ARG a) => | ||
400 : | (case a of | ||
401 : | T.LOAD (_, addr, region) => | ||
402 : | dwordmemarg (addr, region, []) | ||
403 : | | _ => dwordarg (fn addr => | ||
404 : | T.STORE (64, addr, a, stack))) | ||
405 : | | (Ty.C_float, FARG a) => | ||
406 : | (* we use the stack region reserved for storing | ||
407 : | * %o0-%o5 as temporary storage for transferring | ||
408 : | * floating point values *) | ||
409 : | (case a of | ||
410 : | T.FLOAD (_, addr, region) => | ||
411 : | wordarg (T.LOAD (32, addr, region), cpc, ss) | ||
412 : | | _ => | ||
413 : | if n < 6 then let | ||
414 : | val ld = T.MV (32, oreg n, | ||
415 : | T.LOAD (32, tmpaddr, stack)) | ||
416 : | val cp = T.FSTORE (32, tmpaddr, a, stack) | ||
417 : | in | ||
418 : | loop (tl, al, n + 1, ss, cp :: ld :: asc, cpc) | ||
419 : | end | ||
420 : | else loop (tl, al, n + 1, ss, | ||
421 : | T.FSTORE (32, argaddr n, a, stack) | ||
422 : | :: asc, | ||
423 : | cpc)) | ||
424 : | | (Ty.C_double, FARG a) => | ||
425 : | (case a of | ||
426 : | T.FLOAD (_, addr, region) => | ||
427 : | dwordmemarg (addr, region, []) | ||
428 : | | _ => dwordarg (fn addr => | ||
429 : | T.FSTORE (64, addr, a, stack))) | ||
430 : | | (Ty.C_long_double, FARG a) => let | ||
431 : | (* Copy 128-bit floating point value (16 bytes) | ||
432 : | * into scratch space (aligned at 8-byte boundary). | ||
433 : | * The address of the scratch copy is then | ||
434 : | * passed as a regular 32-bit argument. *) | ||
435 : | val ss' = roundup (ss, 8) | ||
436 : | val ssaddr = addli (spreg, ss') | ||
437 : | in | ||
438 : | wordarg (ssaddr, | ||
439 : | T.FSTORE (128, ssaddr, a, stack) :: cpc, | ||
440 : | ss' + 16) | ||
441 : | end | ||
442 : | | (t as Ty.C_STRUCT _, a) => let | ||
443 : | (* copy entire struct into scratch space | ||
444 : | * (aligned according to struct's alignment | ||
445 : | * requirements). The address of the scratch | ||
446 : | * copy is then passed as a regular 32-bit | ||
447 : | * argument. *) | ||
448 : | val (sz, al) = szal t | ||
449 : | val ss' = roundup (ss, al) | ||
450 : | val ssaddr = addli (spreg, ss') | ||
451 : | val cpc' = struct_copy (sz, al, a, t, ss', cpc) | ||
452 : | in | ||
453 : | wordarg (ssaddr, cpc', ss' + sz) | ||
454 : | end | ||
455 : | | _ => error "argument/type mismatch" | ||
456 : | end | ||
457 : | | loop _ = error "wrong number of arguments" | ||
458 : | in | ||
459 : | loop (paramTys, args, 0, scratchstart, [], []) | ||
460 : | end | ||
461 : | |||
462 : | val (defs, uses) = let | ||
463 : | val gp = T.GPR o reg32 | ||
464 : | val fp = T.FPR o freg64 | ||
465 : | val g_regs = map (gp o greg) [1, 2, 3, 4, 5, 6, 7] | ||
466 : | val a_regs = map (gp o oreg) [0, 1, 2, 3, 4, 5] | ||
467 : | val l_reg = gp (oreg 7) | ||
468 : | val f_regs = map (fp o freg) | ||
469 : | [0, 2, 4, 6, 8, 10, 12, 14, | ||
470 : | 16, 18, 20, 22, 24, 26, 28, 30] | ||
471 : | (* a call instruction defines all caller-save registers: | ||
472 : | * - %g1 - %g7 | ||
473 : | * - %o0 - %o5 (argument registers) | ||
474 : | * - %o7 (link register) | ||
475 : | * - all fp registers *) | ||
476 : | |||
477 : | val defs = g_regs @ a_regs @ l_reg :: f_regs | ||
478 : | (* A call instruction "uses" just the argument registers. *) | ||
479 : | val uses = List.take (a_regs, regargwords) | ||
480 : | in | ||
481 : | (defs, uses) | ||
482 : | end | ||
483 : | |||
484 : | val result = | ||
485 : | case retTy of | ||
486 : | Ty.C_float => [T.FPR (T.FREG (32, FP 0))] | ||
487 : | | Ty.C_double => [T.FPR (T.FREG (64, FP 0))] (* %f0/%f1 *) | ||
488 : | | Ty.C_long_double => [] | ||
489 : | | Ty.C_STRUCT _ => [] | ||
490 : | | Ty.C_ARRAY _ => error "array return type" | ||
491 : | | (Ty.C_PTR | Ty.C_void | | ||
492 : | Ty.C_signed (Ty.I_int | Ty.I_long) | | ||
493 : | Ty.C_unsigned (Ty.I_int | Ty.I_long)) => | ||
494 : | [T.GPR (T.REG (32, oreg 0))] | ||
495 : | | (Ty.C_signed Ty.I_char | Ty.C_unsigned Ty.I_char) => | ||
496 : | [T.GPR (T.REG (8, oreg 0))] | ||
497 : | | (Ty.C_signed Ty.I_short | Ty.C_unsigned Ty.I_short) => | ||
498 : | [T.GPR (T.REG (16, oreg 0))] | ||
499 : | | (Ty.C_signed Ty.I_long_long | Ty.C_unsigned Ty.I_long_long) => | ||
500 : | [T.GPR (T.REG (64, oreg 0))] | ||
501 : | |||
502 : | val { save, restore } = saveRestoreDedicated defs | ||
503 : | |||
504 : | val (sretsetup, srethandshake) = | ||
505 : | case res_szal of | ||
506 : | NONE => ([], []) | ||
507 : | | SOME (sz, al) => let | ||
508 : | val addr = structRet { szb = sz, align = al } | ||
509 : | in | ||
510 : | ([T.STORE (32, addli (spreg, 64), addr, stack)], | ||
511 : | [T.EXT (ix (IX.UNIMP sz))]) | ||
512 : | end | ||
513 : | |||
514 : | val call = T.CALL { funct = name, targets = [], | ||
515 : | defs = defs, uses = uses, | ||
516 : | region = mem, pops = 0 } | ||
517 : | |||
518 : | val call = | ||
519 : | case callComment of | ||
520 : | NONE => call | ||
521 : | | SOME c => | ||
522 : | T.ANNOTATION (call, #create MLRiscAnnotations.COMMENT c) | ||
523 : | |||
524 : | val (sp_sub, sp_add) = | ||
525 : | if stackdelta = 0 then ([], []) else | ||
526 : | if paramAlloc { szb = stackdelta, align = 4 } then ([], []) | ||
527 : | else ([T.MV (32, sp, T.SUB (32, spreg, LI stackdelta))], | ||
528 : | [T.MV (32, sp, addli (spreg, stackdelta))]) | ||
529 : | |||
530 : | val callseq = | ||
531 : | List.concat [sp_sub, | ||
532 : | copycode, | ||
533 : | argsetupcode, | ||
534 : | sretsetup, | ||
535 : | save, | ||
536 : | [call], | ||
537 : | srethandshake, | ||
538 : | restore, | ||
539 : | sp_add] | ||
540 : | |||
541 : | in | ||
542 : | { callseq = callseq, result = result } | ||
543 : | end | ||
544 : | end |
root@smlnj-gforge.cs.uchicago.edu | ViewVC Help |
Powered by ViewVC 1.0.0 |