1a0314052163528e5688015b403ab2c348bc2dec
[ghc.git] / utils / genapply / GenApply.hs
1 {-# OPTIONS -cpp #-}
2 module Main(main) where
3
4 #include "../../includes/ghcconfig.h"
5 #include "../../includes/MachRegs.h"
6 #include "../../includes/Constants.h"
7
8
9 import Text.PrettyPrint
10 import Data.Word
11 import Data.Bits
12 import Data.List ( intersperse )
13 import System.Exit
14 import System.Environment
15 import System.IO
16
17 -- -----------------------------------------------------------------------------
18 -- Argument kinds (rougly equivalent to PrimRep)
19
20 data ArgRep
21 = N -- non-ptr
22 | P -- ptr
23 | V -- void
24 | F -- float
25 | D -- double
26 | L -- long (64-bit)
27
28 -- size of a value in *words*
29 argSize :: ArgRep -> Int
30 argSize N = 1
31 argSize P = 1
32 argSize V = 0
33 argSize F = 1
34 argSize D = (SIZEOF_DOUBLE `quot` SIZEOF_VOID_P :: Int)
35 argSize L = (8 `quot` SIZEOF_VOID_P :: Int)
36
37 showArg :: ArgRep -> Char
38 showArg N = 'n'
39 showArg P = 'p'
40 showArg V = 'v'
41 showArg F = 'f'
42 showArg D = 'd'
43 showArg L = 'l'
44
45 -- is a value a pointer?
46 isPtr :: ArgRep -> Bool
47 isPtr P = True
48 isPtr _ = False
49
50 -- -----------------------------------------------------------------------------
51 -- Registers
52
53 data RegStatus = Registerised | Unregisterised
54
55 type Reg = String
56
57 availableRegs :: RegStatus -> ([Reg],[Reg],[Reg],[Reg])
58 availableRegs Unregisterised = ([],[],[],[])
59 availableRegs Registerised =
60 ( vanillaRegs MAX_REAL_VANILLA_REG,
61 floatRegs MAX_REAL_FLOAT_REG,
62 doubleRegs MAX_REAL_DOUBLE_REG,
63 longRegs MAX_REAL_LONG_REG
64 )
65
66 vanillaRegs, floatRegs, doubleRegs, longRegs :: Int -> [Reg]
67 vanillaRegs n = [ "R" ++ show m | m <- [2..n] ] -- never use R1
68 floatRegs n = [ "F" ++ show m | m <- [1..n] ]
69 doubleRegs n = [ "D" ++ show m | m <- [1..n] ]
70 longRegs n = [ "L" ++ show m | m <- [1..n] ]
71
72 -- -----------------------------------------------------------------------------
73 -- Loading/saving register arguments to the stack
74
75 loadRegArgs :: RegStatus -> Int -> [ArgRep] -> (Doc,Int)
76 loadRegArgs regstatus sp args
77 = (loadRegOffs reg_locs, sp')
78 where (reg_locs, _, sp') = assignRegs regstatus sp args
79
80 loadRegOffs :: [(Reg,Int)] -> Doc
81 loadRegOffs = vcat . map (uncurry assign_stk_to_reg)
82
83 saveRegOffs :: [(Reg,Int)] -> Doc
84 saveRegOffs = vcat . map (uncurry assign_reg_to_stk)
85
86 -- a bit like assignRegs in CgRetConv.lhs
87 assignRegs
88 :: RegStatus -- are we registerised?
89 -> Int -- Sp of first arg
90 -> [ArgRep] -- args
91 -> ([(Reg,Int)], -- regs and offsets to load
92 [ArgRep], -- left-over args
93 Int) -- Sp of left-over args
94 assignRegs regstatus sp args = assign sp args (availableRegs regstatus) []
95
96 assign sp [] regs doc = (doc, [], sp)
97 assign sp (V : args) regs doc = assign sp args regs doc
98 assign sp (arg : args) regs doc
99 = case findAvailableReg arg regs of
100 Just (reg, regs') -> assign (sp + argSize arg) args regs'
101 ((reg, sp) : doc)
102 Nothing -> (doc, (arg:args), sp)
103
104 findAvailableReg N (vreg:vregs, fregs, dregs, lregs) =
105 Just (vreg, (vregs,fregs,dregs,lregs))
106 findAvailableReg P (vreg:vregs, fregs, dregs, lregs) =
107 Just (vreg, (vregs,fregs,dregs,lregs))
108 findAvailableReg F (vregs, freg:fregs, dregs, lregs) =
109 Just (freg, (vregs,fregs,dregs,lregs))
110 findAvailableReg D (vregs, fregs, dreg:dregs, lregs) =
111 Just (dreg, (vregs,fregs,dregs,lregs))
112 findAvailableReg L (vregs, fregs, dregs, lreg:lregs) =
113 Just (lreg, (vregs,fregs,dregs,lregs))
114 findAvailableReg _ _ = Nothing
115
116 assign_reg_to_stk reg sp
117 = loadSpWordOff (regRep reg) sp <> text " = " <> text reg <> semi
118
119 assign_stk_to_reg reg sp
120 = text reg <> text " = " <> loadSpWordOff (regRep reg) sp <> semi
121
122 regRep ('F':_) = "F_"
123 regRep ('D':_) = "D_"
124 regRep ('L':_) = "L_"
125 regRep _ = "W_"
126
127 loadSpWordOff :: String -> Int -> Doc
128 loadSpWordOff rep off = text rep <> text "[Sp+WDS(" <> int off <> text ")]"
129
130 -- make a ptr/non-ptr bitmap from a list of argument types
131 mkBitmap :: [ArgRep] -> Word32
132 mkBitmap args = foldr f 0 args
133 where f arg bm | isPtr arg = bm `shiftL` 1
134 | otherwise = (bm `shiftL` size) .|. ((1 `shiftL` size) - 1)
135 where size = argSize arg
136
137 -- -----------------------------------------------------------------------------
138 -- Generating the application functions
139
140 -- A SUBTLE POINT about stg_ap functions (can't think of a better
141 -- place to put this comment --SDM):
142 --
143 -- The entry convention to an stg_ap_ function is as follows: all the
144 -- arguments are on the stack (we might revisit this at some point,
145 -- but it doesn't make any difference on x86), and THERE IS AN EXTRA
146 -- EMPTY STACK SLOT at the top of the stack.
147 --
148 -- Why? Because in several cases, stg_ap_* will need an extra stack
149 -- slot, eg. to push a return address in the THUNK case, and this is a
150 -- way of pushing the stack check up into the caller which is probably
151 -- doing one anyway. Allocating the extra stack slot in the caller is
152 -- also probably free, because it will be adjusting Sp after pushing
153 -- the args anyway (this might not be true of register-rich machines
154 -- when we start passing args to stg_ap_* in regs).
155
156 mkApplyName args
157 = text "stg_ap_" <> text (map showArg args)
158
159 mkApplyRetName args
160 = mkApplyName args <> text "_ret"
161
162 mkApplyFastName args
163 = mkApplyName args <> text "_fast"
164
165 mkApplyInfoName args
166 = mkApplyName args <> text "_info"
167
168 genMkPAP regstatus macro jump ticker disamb
169 no_load_regs -- don't load argumnet regs before jumping
170 args_in_regs -- arguments are already in regs
171 is_pap args all_args_size fun_info_label
172 = smaller_arity_cases
173 $$ exact_arity_case
174 $$ larger_arity_case
175
176 where
177 n_args = length args
178
179 -- offset of arguments on the stack at slow apply calls.
180 stk_args_slow_offset = 1
181
182 stk_args_offset
183 | args_in_regs = 0
184 | otherwise = stk_args_slow_offset
185
186 -- The SMALLER ARITY cases:
187 -- if (arity == 1) {
188 -- Sp[0] = Sp[1];
189 -- Sp[1] = (W_)&stg_ap_1_info;
190 -- JMP_(GET_ENTRY(R1.cl));
191 smaller_arity_cases = vcat [ smaller_arity i | i <- [1..n_args-1] ]
192
193 smaller_arity arity
194 = text "if (arity == " <> int arity <> text ") {" $$
195 nest 4 (vcat [
196 -- text "TICK_SLOW_CALL_" <> text ticker <> text "_TOO_MANY();",
197
198 -- load up regs for the call, if necessary
199 load_regs,
200
201 -- If we have more args in registers than are required
202 -- for the call, then we must save some on the stack,
203 -- and set up the stack for the follow-up call.
204 -- If the extra arguments are on the stack, then we must
205 -- instead shuffle them down to make room for the info
206 -- table for the follow-on call.
207 if overflow_regs
208 then save_extra_regs
209 else shuffle_extra_args,
210
211 -- for a PAP, we have to arrange that the stack contains a
212 -- return address in the even that stg_PAP_entry fails its
213 -- heap check. See stg_PAP_entry in Apply.hc for details.
214 if is_pap
215 then text "R2 = " <> mkApplyInfoName this_call_args <> semi
216
217 else empty,
218 text "jump " <> text jump <> semi
219 ]) $$
220 text "}"
221
222 where
223 -- offsets in case we need to save regs:
224 (reg_locs, _, _)
225 = assignRegs regstatus stk_args_offset args
226
227 -- register assignment for *this function call*
228 (reg_locs', reg_call_leftovers, reg_call_sp_stk_args)
229 = assignRegs regstatus stk_args_offset (take arity args)
230
231 load_regs
232 | no_load_regs || args_in_regs = empty
233 | otherwise = loadRegOffs reg_locs'
234
235 (this_call_args, rest_args) = splitAt arity args
236
237 -- the offset of the stack args from initial Sp
238 sp_stk_args
239 | args_in_regs = stk_args_offset
240 | no_load_regs = stk_args_offset
241 | otherwise = reg_call_sp_stk_args
242
243 -- the stack args themselves
244 this_call_stack_args
245 | args_in_regs = reg_call_leftovers -- sp offsets are wrong
246 | no_load_regs = this_call_args
247 | otherwise = reg_call_leftovers
248
249 stack_args_size = sum (map argSize this_call_stack_args)
250
251 overflow_regs = args_in_regs && length reg_locs > length reg_locs'
252
253 save_extra_regs
254 = -- we have extra arguments in registers to save
255 let
256 extra_reg_locs = drop (length reg_locs') (reverse reg_locs)
257 adj_reg_locs = [ (reg, off - adj + 1) |
258 (reg,off) <- extra_reg_locs ]
259 adj = case extra_reg_locs of
260 (reg, fst_off):_ -> fst_off
261 size = snd (last adj_reg_locs)
262 in
263 text "Sp_adj(" <> int (-size - 1) <> text ");" $$
264 saveRegOffs adj_reg_locs $$
265 loadSpWordOff "W_" 0 <> text " = " <>
266 mkApplyInfoName rest_args <> semi
267
268 shuffle_extra_args
269 = vcat (map shuffle_down
270 [sp_stk_args .. sp_stk_args+stack_args_size-1]) $$
271 loadSpWordOff "W_" (sp_stk_args+stack_args_size-1)
272 <> text " = "
273 <> mkApplyInfoName rest_args <> semi $$
274 text "Sp_adj(" <> int (sp_stk_args - 1) <> text ");"
275
276 shuffle_down i =
277 loadSpWordOff "W_" (i-1) <> text " = " <>
278 loadSpWordOff "W_" i <> semi
279
280 -- The EXACT ARITY case
281 --
282 -- if (arity == 1) {
283 -- Sp++;
284 -- JMP_(GET_ENTRY(R1.cl));
285
286 exact_arity_case
287 = text "if (arity == " <> int n_args <> text ") {" $$
288 let
289 (reg_doc, sp')
290 | no_load_regs || args_in_regs = (empty, stk_args_offset)
291 | otherwise = loadRegArgs regstatus stk_args_offset args
292 in
293 nest 4 (vcat [
294 -- text "TICK_SLOW_CALL_" <> text ticker <> text "_CORRECT();",
295 reg_doc,
296 text "Sp_adj(" <> int sp' <> text ");",
297 if is_pap
298 then text "R2 = " <> fun_info_label <> semi
299 else empty,
300 text "jump " <> text jump <> semi
301 ])
302
303 -- The LARGER ARITY cases:
304 --
305 -- } else /* arity > 1 */ {
306 -- BUILD_PAP(1,0,(W_)&stg_ap_v_info);
307 -- }
308
309 larger_arity_case =
310 text "} else {" $$
311 let
312 save_regs
313 | args_in_regs =
314 text "Sp_adj(" <> int (-sp_offset) <> text ");" $$
315 saveRegOffs reg_locs
316 | otherwise =
317 empty
318 in
319 nest 4 (vcat [
320 -- text "TICK_SLOW_CALL_" <> text ticker <> text "_TOO_FEW();",
321 save_regs,
322 text macro <> char '(' <> int n_args <> comma <>
323 int all_args_size <>
324 text "," <> fun_info_label <>
325 text "," <> text disamb <>
326 text ");"
327 ]) $$
328 char '}'
329 where
330 -- offsets in case we need to save regs:
331 (reg_locs, leftovers, sp_offset)
332 = assignRegs regstatus stk_args_slow_offset args
333 -- BUILD_PAP assumes args start at offset 1
334
335 -- -----------------------------------------------------------------------------
336 -- generate an apply function
337
338 -- args is a list of 'p', 'n', 'f', 'd' or 'l'
339
340 genApply regstatus args =
341 let
342 fun_ret_label = mkApplyRetName args
343 fun_info_label = mkApplyInfoName args
344 all_args_size = sum (map argSize args)
345 in
346 vcat [
347 text "INFO_TABLE_RET(" <> mkApplyName args <> text ", " <>
348 int all_args_size <> text "/*framsize*/," <>
349 int (fromIntegral (mkBitmap args)) <> text "/*bitmap*/, " <>
350 text "RET_SMALL)\n{",
351 nest 4 (vcat [
352 text "W_ info;",
353 text "W_ arity;",
354
355 -- if fast == 1:
356 -- print "static void *lbls[] ="
357 -- print " { [FUN] &&fun_lbl,"
358 -- print " [FUN_1_0] &&fun_lbl,"
359 -- print " [FUN_0_1] &&fun_lbl,"
360 -- print " [FUN_2_0] &&fun_lbl,"
361 -- print " [FUN_1_1] &&fun_lbl,"
362 -- print " [FUN_0_2] &&fun_lbl,"
363 -- print " [FUN_STATIC] &&fun_lbl,"
364 -- print " [PAP] &&pap_lbl,"
365 -- print " [THUNK] &&thunk_lbl,"
366 -- print " [THUNK_1_0] &&thunk_lbl,"
367 -- print " [THUNK_0_1] &&thunk_lbl,"
368 -- print " [THUNK_2_0] &&thunk_lbl,"
369 -- print " [THUNK_1_1] &&thunk_lbl,"
370 -- print " [THUNK_0_2] &&thunk_lbl,"
371 -- print " [THUNK_STATIC] &&thunk_lbl,"
372 -- print " [THUNK_SELECTOR] &&thunk_lbl,"
373 -- print " [IND] &&ind_lbl,"
374 -- print " [IND_OLDGEN] &&ind_lbl,"
375 -- print " [IND_STATIC] &&ind_lbl,"
376 -- print " [IND_PERM] &&ind_lbl,"
377 -- print " [IND_OLDGEN_PERM] &&ind_lbl"
378 -- print " };"
379
380 text "",
381 text "IF_DEBUG(apply,foreign \"C\" debugBelch(\"" <> fun_ret_label <>
382 text "... \"); foreign \"C\" printClosure(R1 \"ptr\"));",
383
384 text "IF_DEBUG(sanity,foreign \"C\" checkStackFrame(Sp+WDS(" <> int (1 + all_args_size)
385 <> text ")\"ptr\"));",
386
387 -- text "IF_DEBUG(sanity,checkStackChunk(Sp+" <> int (1 + all_args_size) <>
388 -- text ", CurrentTSO->stack + CurrentTSO->stack_size));",
389
390 -- text "TICK_SLOW_CALL(" <> int (length args) <> text ");",
391
392 let do_assert [] _ = []
393 do_assert (arg:args) offset
394 | isPtr arg = this : rest
395 | otherwise = rest
396 where this = text "ASSERT(LOOKS_LIKE_CLOSURE_PTR(Sp("
397 <> int offset <> text ")));"
398 rest = do_assert args (offset + argSize arg)
399 in
400 vcat (do_assert args 1),
401
402 text "again:",
403 text "info = %INFO_PTR(R1);",
404
405 -- if fast == 1:
406 -- print " goto *lbls[info->type];";
407 -- else:
408 text "switch [INVALID_OBJECT .. N_CLOSURE_TYPES] (TO_W_(%INFO_TYPE(%STD_INFO(info)))) {",
409 nest 4 (vcat [
410
411 -- if fast == 1:
412 -- print " bco_lbl:"
413 -- else:
414 text "case BCO: {",
415 nest 4 (vcat [
416 text "arity = TO_W_(StgBCO_arity(R1));",
417 text "ASSERT(arity > 0);",
418 genMkPAP regstatus "BUILD_PAP" "ENTRY_LBL(stg_BCO)" "FUN" "BCO"
419 True{-stack apply-} False{-args on stack-} False{-not a PAP-}
420 args all_args_size fun_info_label
421 ]),
422 text "}",
423
424 -- if fast == 1:
425 -- print " fun_lbl:"
426 -- else:
427 text "case FUN,",
428 text " FUN_1_0,",
429 text " FUN_0_1,",
430 text " FUN_2_0,",
431 text " FUN_1_1,",
432 text " FUN_0_2,",
433 text " FUN_STATIC: {",
434 nest 4 (vcat [
435 text "arity = TO_W_(StgFunInfoExtra_arity(%FUN_INFO(info)));",
436 text "ASSERT(arity > 0);",
437 genMkPAP regstatus "BUILD_PAP" "%GET_ENTRY(R1)" "FUN" "FUN"
438 False{-reg apply-} False{-args on stack-} False{-not a PAP-}
439 args all_args_size fun_info_label
440 ]),
441 text "}",
442
443 -- if fast == 1:
444 -- print " pap_lbl:"
445 -- else:
446
447 text "case PAP: {",
448 nest 4 (vcat [
449 text "arity = TO_W_(StgPAP_arity(R1));",
450 text "ASSERT(arity > 0);",
451 genMkPAP regstatus "NEW_PAP" "stg_PAP_apply" "PAP" "PAP"
452 True{-stack apply-} False{-args on stack-} True{-is a PAP-}
453 args all_args_size fun_info_label
454 ]),
455 text "}",
456
457 text "",
458
459 -- if fast == 1:
460 -- print " thunk_lbl:"
461 -- else:
462 text "case AP,",
463 text " AP_STACK,",
464 text " CAF_BLACKHOLE,",
465 text " BLACKHOLE,",
466 text " SE_BLACKHOLE,",
467 text " SE_CAF_BLACKHOLE,",
468 text " THUNK,",
469 text " THUNK_1_0,",
470 text " THUNK_0_1,",
471 text " THUNK_2_0,",
472 text " THUNK_1_1,",
473 text " THUNK_0_2,",
474 text " THUNK_STATIC,",
475 text " THUNK_SELECTOR: {",
476 nest 4 (vcat [
477 -- text "TICK_SLOW_CALL_UNEVALD(" <> int (length args) <> text ");",
478 text "Sp(0) = " <> fun_info_label <> text ";",
479 -- CAREFUL! in SMP mode, the info table may already have been
480 -- overwritten by an indirection, so we must enter the original
481 -- info pointer we read, don't read it again, because it might
482 -- not be enterable any more.
483 text "jump %ENTRY_CODE(info);",
484 text ""
485 ]),
486 text "}",
487
488 -- if fast == 1:
489 -- print " ind_lbl:"
490 -- else:
491 text "case IND,",
492 text " IND_OLDGEN,",
493 text " IND_STATIC,",
494 text " IND_PERM,",
495 text " IND_OLDGEN_PERM: {",
496 nest 4 (vcat [
497 text "R1 = StgInd_indirectee(R1);",
498 text "goto again;"
499 ]),
500 text "}",
501 text "",
502
503 -- if fast == 0:
504
505 text "default: {",
506 nest 4 (
507 text "foreign \"C\" barf(\"" <> fun_ret_label <> text "\");"
508 ),
509 text "}"
510
511 ]),
512 text "}"
513 ]),
514 text "}"
515 ]
516
517 -- -----------------------------------------------------------------------------
518 -- Making a fast unknown application, args are in regs
519
520 genApplyFast regstatus args =
521 let
522 fun_fast_label = mkApplyFastName args
523 fun_ret_label = text "RET_LBL" <> parens (mkApplyName args)
524 fun_info_label = mkApplyInfoName args
525 all_args_size = sum (map argSize args)
526 in
527 vcat [
528 fun_fast_label,
529 char '{',
530 nest 4 (vcat [
531 text "W_ info;",
532 text "W_ arity;",
533 text "info = %GET_STD_INFO(R1);",
534 text "switch [INVALID_OBJECT .. N_CLOSURE_TYPES] (TO_W_(%INFO_TYPE(info))) {",
535 nest 4 (vcat [
536 text "case FUN,",
537 text " FUN_1_0,",
538 text " FUN_0_1,",
539 text " FUN_2_0,",
540 text " FUN_1_1,",
541 text " FUN_0_2,",
542 text " FUN_STATIC: {",
543 nest 4 (vcat [
544 text "arity = TO_W_(StgFunInfoExtra_arity(%GET_FUN_INFO(R1)));",
545 text "ASSERT(arity > 0);",
546 genMkPAP regstatus "BUILD_PAP" "%GET_ENTRY(R1)" "FUN" "FUN"
547 False{-reg apply-} True{-args in regs-} False{-not a PAP-}
548 args all_args_size fun_info_label
549 ]),
550 char '}',
551
552 text "default: {",
553 let
554 (reg_locs, leftovers, sp_offset) = assignRegs regstatus 1 args
555 -- leave a one-word space on the top of the stack when
556 -- calling the slow version
557 in
558 nest 4 (vcat [
559 text "Sp_adj" <> parens (int (-sp_offset)) <> semi,
560 saveRegOffs reg_locs,
561 text "jump" <+> fun_ret_label <> semi
562 ]),
563 char '}'
564 ]),
565 char '}'
566 ]),
567 char '}'
568 ]
569
570 -- -----------------------------------------------------------------------------
571 -- Making a stack apply
572
573 -- These little functions are like slow entry points. They provide
574 -- the layer between the PAP entry code and the function's fast entry
575 -- point: namely they load arguments off the stack into registers (if
576 -- available) and jump to the function's entry code.
577 --
578 -- On entry: R1 points to the function closure
579 -- arguments are on the stack starting at Sp
580 --
581 -- Invariant: the list of arguments never contains void. Since we're only
582 -- interested in loading arguments off the stack here, we can ignore
583 -- void arguments.
584
585 mkStackApplyEntryLabel:: [ArgRep] -> Doc
586 mkStackApplyEntryLabel args = text "stg_ap_stk_" <> text (map showArg args)
587
588 genStackApply :: RegStatus -> [ArgRep] -> Doc
589 genStackApply regstatus args =
590 let fn_entry_label = mkStackApplyEntryLabel args in
591 vcat [
592 fn_entry_label,
593 text "{", nest 4 body, text "}"
594 ]
595 where
596 (assign_regs, sp') = loadRegArgs regstatus 0 args
597 body = vcat [assign_regs,
598 text "Sp_adj" <> parens (int sp') <> semi,
599 text "jump %GET_ENTRY(R1);"
600 ]
601
602 -- -----------------------------------------------------------------------------
603 -- Stack save entry points.
604 --
605 -- These code fragments are used to save registers on the stack at a heap
606 -- check failure in the entry code for a function. We also have to save R1
607 -- and the return address (stg_gc_fun_info) on the stack. See stg_gc_fun_gen
608 -- in HeapStackCheck.hc for more details.
609
610 mkStackSaveEntryLabel :: [ArgRep] -> Doc
611 mkStackSaveEntryLabel args = text "stg_stk_save_" <> text (map showArg args)
612
613 genStackSave :: RegStatus -> [ArgRep] -> Doc
614 genStackSave regstatus args =
615 let fn_entry_label= mkStackSaveEntryLabel args in
616 vcat [
617 fn_entry_label,
618 text "{", nest 4 body, text "}"
619 ]
620 where
621 body = vcat [text "Sp_adj" <> parens (int (-sp_offset)) <> semi,
622 saveRegOffs reg_locs,
623 text "Sp(2) = R1;",
624 text "Sp(1) =" <+> int stk_args <> semi,
625 text "Sp(0) = stg_gc_fun_info;",
626 text "jump stg_gc_noregs;"
627 ]
628
629 std_frame_size = 3 -- the std bits of the frame. See StgRetFun in Closures.h,
630 -- and the comment on stg_fun_gc_gen in HeapStackCheck.hc.
631 (reg_locs, leftovers, sp_offset) = assignRegs regstatus std_frame_size args
632
633 -- number of words of arguments on the stack.
634 stk_args = sum (map argSize leftovers) + sp_offset - std_frame_size
635
636 -- -----------------------------------------------------------------------------
637 -- The prologue...
638
639 main = do
640 args <- getArgs
641 regstatus <- case args of
642 [] -> return Registerised
643 ["-u"] -> return Unregisterised
644 _other -> do hPutStrLn stderr "syntax: genapply [-u]"
645 exitWith (ExitFailure 1)
646 let the_code = vcat [
647 text "// DO NOT EDIT!",
648 text "// Automatically generated by GenApply.hs",
649 text "",
650 text "#include \"Cmm.h\"",
651 text "#include \"AutoApply.h\"",
652 text "",
653
654 vcat (intersperse (text "") $
655 map (genApply regstatus) applyTypes),
656 vcat (intersperse (text "") $
657 map (genStackFns regstatus) stackApplyTypes),
658
659 vcat (intersperse (text "") $
660 map (genApplyFast regstatus) applyTypes),
661
662 genStackApplyArray stackApplyTypes,
663 genStackSaveArray stackApplyTypes,
664 genBitmapArray stackApplyTypes,
665
666 text "" -- add a newline at the end of the file
667 ]
668 -- in
669 putStr (render the_code)
670
671 -- These have been shown to cover about 99% of cases in practice...
672 applyTypes = [
673 [V],
674 [F],
675 [D],
676 [L],
677 [N],
678 [P],
679 [P,V],
680 [P,P],
681 [P,P,V],
682 [P,P,P],
683 [P,P,P,V],
684 [P,P,P,P],
685 [P,P,P,P,P],
686 [P,P,P,P,P,P]
687 ]
688
689 -- No need for V args in the stack apply cases.
690 -- ToDo: the stack apply and stack save code doesn't make a distinction
691 -- between N and P (they both live in the same register), only the bitmap
692 -- changes, so we could share the apply/save code between lots of cases.
693 stackApplyTypes = [
694 [],
695 [N],
696 [P],
697 [F],
698 [D],
699 [L],
700 [N,N],
701 [N,P],
702 [P,N],
703 [P,P],
704 [N,N,N],
705 [N,N,P],
706 [N,P,N],
707 [N,P,P],
708 [P,N,N],
709 [P,N,P],
710 [P,P,N],
711 [P,P,P],
712 [P,P,P,P],
713 [P,P,P,P,P],
714 [P,P,P,P,P,P],
715 [P,P,P,P,P,P,P],
716 [P,P,P,P,P,P,P,P]
717 ]
718
719 genStackFns regstatus args
720 = genStackApply regstatus args
721 $$ genStackSave regstatus args
722
723
724 genStackApplyArray types =
725 vcat [
726 text "section \"relrodata\" {",
727 text "stg_ap_stack_entries:",
728 text "W_ 0; W_ 0; W_ 0;", -- ARG_GEN, ARG_GEN_BIG, ARG_BCO
729 vcat (map arr_ent types),
730 text "}"
731 ]
732 where
733 arr_ent ty = text "W_" <+> mkStackApplyEntryLabel ty <> semi
734
735 genStackSaveArray types =
736 vcat [
737 text "section \"relrodata\" {",
738 text "stg_stack_save_entries:",
739 text "W_ 0; W_ 0; W_ 0;", -- ARG_GEN, ARG_GEN_BIG, ARG_BCO
740 vcat (map arr_ent types),
741 text "}"
742 ]
743 where
744 arr_ent ty = text "W_" <+> mkStackSaveEntryLabel ty <> semi
745
746 genBitmapArray :: [[ArgRep]] -> Doc
747 genBitmapArray types =
748 vcat [
749 text "section \"rodata\" {",
750 text "stg_arg_bitmaps:",
751 text "W_ 0; W_ 0; W_ 0;", -- ARG_GEN, ARG_GEN_BIG, ARG_BCO
752 vcat (map gen_bitmap types),
753 text "}"
754 ]
755 where
756 gen_bitmap ty = text "W_" <+> int bitmap_val <> semi
757 where bitmap_val =
758 (fromIntegral (mkBitmap ty) `shiftL` BITMAP_BITS_SHIFT)
759 .|. sum (map argSize ty)
760