| 1 | ----------------------------------------------------------------------------- |
|---|
| 2 | -- |
|---|
| 3 | -- (c) The University of Glasgow 2004-2006 |
|---|
| 4 | -- |
|---|
| 5 | -- CgCallConv |
|---|
| 6 | -- |
|---|
| 7 | -- The datatypes and functions here encapsulate the |
|---|
| 8 | -- calling and return conventions used by the code generator. |
|---|
| 9 | -- |
|---|
| 10 | ----------------------------------------------------------------------------- |
|---|
| 11 | |
|---|
| 12 | module CgCallConv ( |
|---|
| 13 | -- Argument descriptors |
|---|
| 14 | mkArgDescr, |
|---|
| 15 | |
|---|
| 16 | -- Liveness |
|---|
| 17 | mkRegLiveness, |
|---|
| 18 | |
|---|
| 19 | -- Register assignment |
|---|
| 20 | assignCallRegs, assignReturnRegs, assignPrimOpCallRegs, |
|---|
| 21 | |
|---|
| 22 | -- Calls |
|---|
| 23 | constructSlowCall, slowArgs, slowCallPattern, |
|---|
| 24 | |
|---|
| 25 | -- Returns |
|---|
| 26 | dataReturnConvPrim, |
|---|
| 27 | getSequelAmode |
|---|
| 28 | ) where |
|---|
| 29 | |
|---|
| 30 | import CgMonad |
|---|
| 31 | import CgProf |
|---|
| 32 | import SMRep |
|---|
| 33 | |
|---|
| 34 | import OldCmm |
|---|
| 35 | import CLabel |
|---|
| 36 | |
|---|
| 37 | import Constants |
|---|
| 38 | import CgStackery |
|---|
| 39 | import ClosureInfo( CgRep(..), nonVoidArg, idCgRep, cgRepSizeW, isFollowableArg ) |
|---|
| 40 | import OldCmmUtils |
|---|
| 41 | import Maybes |
|---|
| 42 | import Id |
|---|
| 43 | import Name |
|---|
| 44 | import Util |
|---|
| 45 | import StaticFlags |
|---|
| 46 | import Module |
|---|
| 47 | import FastString |
|---|
| 48 | import Outputable |
|---|
| 49 | import Data.Bits |
|---|
| 50 | |
|---|
| 51 | ------------------------------------------------------------------------- |
|---|
| 52 | -- |
|---|
| 53 | -- Making argument descriptors |
|---|
| 54 | -- |
|---|
| 55 | -- An argument descriptor describes the layout of args on the stack, |
|---|
| 56 | -- both for * GC (stack-layout) purposes, and |
|---|
| 57 | -- * saving/restoring registers when a heap-check fails |
|---|
| 58 | -- |
|---|
| 59 | -- Void arguments aren't important, therefore (contrast constructSlowCall) |
|---|
| 60 | -- |
|---|
| 61 | ------------------------------------------------------------------------- |
|---|
| 62 | |
|---|
| 63 | -- bring in ARG_P, ARG_N, etc. |
|---|
| 64 | #include "../includes/rts/storage/FunTypes.h" |
|---|
| 65 | |
|---|
| 66 | ------------------------- |
|---|
| 67 | mkArgDescr :: Name -> [Id] -> FCode ArgDescr |
|---|
| 68 | mkArgDescr _nm args |
|---|
| 69 | = case stdPattern arg_reps of |
|---|
| 70 | Just spec_id -> return (ArgSpec spec_id) |
|---|
| 71 | Nothing -> return (ArgGen arg_bits) |
|---|
| 72 | where |
|---|
| 73 | arg_bits = argBits arg_reps |
|---|
| 74 | arg_reps = filter nonVoidArg (map idCgRep args) |
|---|
| 75 | -- Getting rid of voids eases matching of standard patterns |
|---|
| 76 | |
|---|
| 77 | argBits :: [CgRep] -> [Bool] -- True for non-ptr, False for ptr |
|---|
| 78 | argBits [] = [] |
|---|
| 79 | argBits (PtrArg : args) = False : argBits args |
|---|
| 80 | argBits (arg : args) = take (cgRepSizeW arg) (repeat True) ++ argBits args |
|---|
| 81 | |
|---|
| 82 | stdPattern :: [CgRep] -> Maybe StgHalfWord |
|---|
| 83 | stdPattern [] = Just ARG_NONE -- just void args, probably |
|---|
| 84 | |
|---|
| 85 | stdPattern [PtrArg] = Just ARG_P |
|---|
| 86 | stdPattern [FloatArg] = Just ARG_F |
|---|
| 87 | stdPattern [DoubleArg] = Just ARG_D |
|---|
| 88 | stdPattern [LongArg] = Just ARG_L |
|---|
| 89 | stdPattern [NonPtrArg] = Just ARG_N |
|---|
| 90 | |
|---|
| 91 | stdPattern [NonPtrArg,NonPtrArg] = Just ARG_NN |
|---|
| 92 | stdPattern [NonPtrArg,PtrArg] = Just ARG_NP |
|---|
| 93 | stdPattern [PtrArg,NonPtrArg] = Just ARG_PN |
|---|
| 94 | stdPattern [PtrArg,PtrArg] = Just ARG_PP |
|---|
| 95 | |
|---|
| 96 | stdPattern [NonPtrArg,NonPtrArg,NonPtrArg] = Just ARG_NNN |
|---|
| 97 | stdPattern [NonPtrArg,NonPtrArg,PtrArg] = Just ARG_NNP |
|---|
| 98 | stdPattern [NonPtrArg,PtrArg,NonPtrArg] = Just ARG_NPN |
|---|
| 99 | stdPattern [NonPtrArg,PtrArg,PtrArg] = Just ARG_NPP |
|---|
| 100 | stdPattern [PtrArg,NonPtrArg,NonPtrArg] = Just ARG_PNN |
|---|
| 101 | stdPattern [PtrArg,NonPtrArg,PtrArg] = Just ARG_PNP |
|---|
| 102 | stdPattern [PtrArg,PtrArg,NonPtrArg] = Just ARG_PPN |
|---|
| 103 | stdPattern [PtrArg,PtrArg,PtrArg] = Just ARG_PPP |
|---|
| 104 | |
|---|
| 105 | stdPattern [PtrArg,PtrArg,PtrArg,PtrArg] = Just ARG_PPPP |
|---|
| 106 | stdPattern [PtrArg,PtrArg,PtrArg,PtrArg,PtrArg] = Just ARG_PPPPP |
|---|
| 107 | stdPattern [PtrArg,PtrArg,PtrArg,PtrArg,PtrArg,PtrArg] = Just ARG_PPPPPP |
|---|
| 108 | stdPattern _ = Nothing |
|---|
| 109 | |
|---|
| 110 | |
|---|
| 111 | ------------------------------------------------------------------------- |
|---|
| 112 | -- |
|---|
| 113 | -- Bitmap describing register liveness |
|---|
| 114 | -- across GC when doing a "generic" heap check |
|---|
| 115 | -- (a RET_DYN stack frame). |
|---|
| 116 | -- |
|---|
| 117 | -- NB. Must agree with these macros (currently in StgMacros.h): |
|---|
| 118 | -- GET_NON_PTRS(), GET_PTRS(), GET_LIVENESS(). |
|---|
| 119 | ------------------------------------------------------------------------- |
|---|
| 120 | |
|---|
| 121 | mkRegLiveness :: [(Id, GlobalReg)] -> Int -> Int -> StgWord |
|---|
| 122 | mkRegLiveness regs ptrs nptrs |
|---|
| 123 | = (fromIntegral nptrs `shiftL` 16) .|. |
|---|
| 124 | (fromIntegral ptrs `shiftL` 24) .|. |
|---|
| 125 | all_non_ptrs `xor` reg_bits regs |
|---|
| 126 | where |
|---|
| 127 | all_non_ptrs = 0xff |
|---|
| 128 | |
|---|
| 129 | reg_bits [] = 0 |
|---|
| 130 | reg_bits ((id, VanillaReg i _) : regs) | isFollowableArg (idCgRep id) |
|---|
| 131 | = (1 `shiftL` (i - 1)) .|. reg_bits regs |
|---|
| 132 | reg_bits (_ : regs) |
|---|
| 133 | = reg_bits regs |
|---|
| 134 | |
|---|
| 135 | ------------------------------------------------------------------------- |
|---|
| 136 | -- |
|---|
| 137 | -- Pushing the arguments for a slow call |
|---|
| 138 | -- |
|---|
| 139 | ------------------------------------------------------------------------- |
|---|
| 140 | |
|---|
| 141 | -- For a slow call, we must take a bunch of arguments and intersperse |
|---|
| 142 | -- some stg_ap_<pattern>_ret_info return addresses. |
|---|
| 143 | constructSlowCall |
|---|
| 144 | :: [(CgRep,CmmExpr)] |
|---|
| 145 | -> (CLabel, -- RTS entry point for call |
|---|
| 146 | [(CgRep,CmmExpr)], -- args to pass to the entry point |
|---|
| 147 | [(CgRep,CmmExpr)]) -- stuff to save on the stack |
|---|
| 148 | |
|---|
| 149 | -- don't forget the zero case |
|---|
| 150 | constructSlowCall [] |
|---|
| 151 | = (mkRtsApFastLabel (fsLit "stg_ap_0"), [], []) |
|---|
| 152 | |
|---|
| 153 | constructSlowCall amodes |
|---|
| 154 | = (stg_ap_pat, these, rest) |
|---|
| 155 | where |
|---|
| 156 | stg_ap_pat = mkRtsApFastLabel arg_pat |
|---|
| 157 | (arg_pat, these, rest) = matchSlowPattern amodes |
|---|
| 158 | |
|---|
| 159 | -- | 'slowArgs' takes a list of function arguments and prepares them for |
|---|
| 160 | -- pushing on the stack for "extra" arguments to a function which requires |
|---|
| 161 | -- fewer arguments than we currently have. |
|---|
| 162 | slowArgs :: [(CgRep,CmmExpr)] -> [(CgRep,CmmExpr)] |
|---|
| 163 | slowArgs [] = [] |
|---|
| 164 | slowArgs amodes |
|---|
| 165 | | opt_SccProfilingOn = save_cccs ++ this_pat ++ slowArgs rest |
|---|
| 166 | | otherwise = this_pat ++ slowArgs rest |
|---|
| 167 | where |
|---|
| 168 | (arg_pat, args, rest) = matchSlowPattern amodes |
|---|
| 169 | stg_ap_pat = mkCmmRetInfoLabel rtsPackageId arg_pat |
|---|
| 170 | this_pat = (NonPtrArg, mkLblExpr stg_ap_pat) : args |
|---|
| 171 | save_cccs = [(NonPtrArg, mkLblExpr save_cccs_lbl), (NonPtrArg, curCCS)] |
|---|
| 172 | save_cccs_lbl = mkCmmRetInfoLabel rtsPackageId (fsLit "stg_restore_cccs") |
|---|
| 173 | |
|---|
| 174 | matchSlowPattern :: [(CgRep,CmmExpr)] |
|---|
| 175 | -> (FastString, [(CgRep,CmmExpr)], [(CgRep,CmmExpr)]) |
|---|
| 176 | matchSlowPattern amodes = (arg_pat, these, rest) |
|---|
| 177 | where (arg_pat, n) = slowCallPattern (map fst amodes) |
|---|
| 178 | (these, rest) = splitAt n amodes |
|---|
| 179 | |
|---|
| 180 | -- These cases were found to cover about 99% of all slow calls: |
|---|
| 181 | slowCallPattern :: [CgRep] -> (FastString, Int) |
|---|
| 182 | slowCallPattern (PtrArg: PtrArg: PtrArg: PtrArg: PtrArg: PtrArg: _) = (fsLit "stg_ap_pppppp", 6) |
|---|
| 183 | slowCallPattern (PtrArg: PtrArg: PtrArg: PtrArg: PtrArg: _) = (fsLit "stg_ap_ppppp", 5) |
|---|
| 184 | slowCallPattern (PtrArg: PtrArg: PtrArg: PtrArg: _) = (fsLit "stg_ap_pppp", 4) |
|---|
| 185 | slowCallPattern (PtrArg: PtrArg: PtrArg: VoidArg: _) = (fsLit "stg_ap_pppv", 4) |
|---|
| 186 | slowCallPattern (PtrArg: PtrArg: PtrArg: _) = (fsLit "stg_ap_ppp", 3) |
|---|
| 187 | slowCallPattern (PtrArg: PtrArg: VoidArg: _) = (fsLit "stg_ap_ppv", 3) |
|---|
| 188 | slowCallPattern (PtrArg: PtrArg: _) = (fsLit "stg_ap_pp", 2) |
|---|
| 189 | slowCallPattern (PtrArg: VoidArg: _) = (fsLit "stg_ap_pv", 2) |
|---|
| 190 | slowCallPattern (PtrArg: _) = (fsLit "stg_ap_p", 1) |
|---|
| 191 | slowCallPattern (VoidArg: _) = (fsLit "stg_ap_v", 1) |
|---|
| 192 | slowCallPattern (NonPtrArg: _) = (fsLit "stg_ap_n", 1) |
|---|
| 193 | slowCallPattern (FloatArg: _) = (fsLit "stg_ap_f", 1) |
|---|
| 194 | slowCallPattern (DoubleArg: _) = (fsLit "stg_ap_d", 1) |
|---|
| 195 | slowCallPattern (LongArg: _) = (fsLit "stg_ap_l", 1) |
|---|
| 196 | slowCallPattern _ = panic "CgStackery.slowCallPattern" |
|---|
| 197 | |
|---|
| 198 | ------------------------------------------------------------------------- |
|---|
| 199 | -- |
|---|
| 200 | -- Return conventions |
|---|
| 201 | -- |
|---|
| 202 | ------------------------------------------------------------------------- |
|---|
| 203 | |
|---|
| 204 | dataReturnConvPrim :: CgRep -> CmmReg |
|---|
| 205 | dataReturnConvPrim PtrArg = CmmGlobal (VanillaReg 1 VGcPtr) |
|---|
| 206 | dataReturnConvPrim NonPtrArg = CmmGlobal (VanillaReg 1 VNonGcPtr) |
|---|
| 207 | dataReturnConvPrim LongArg = CmmGlobal (LongReg 1) |
|---|
| 208 | dataReturnConvPrim FloatArg = CmmGlobal (FloatReg 1) |
|---|
| 209 | dataReturnConvPrim DoubleArg = CmmGlobal (DoubleReg 1) |
|---|
| 210 | dataReturnConvPrim VoidArg = panic "dataReturnConvPrim: void" |
|---|
| 211 | |
|---|
| 212 | |
|---|
| 213 | -- getSequelAmode returns an amode which refers to an info table. The info |
|---|
| 214 | -- table will always be of the RET_(BIG|SMALL) kind. We're careful |
|---|
| 215 | -- not to handle real code pointers, just in case we're compiling for |
|---|
| 216 | -- an unregisterised/untailcallish architecture, where info pointers and |
|---|
| 217 | -- code pointers aren't the same. |
|---|
| 218 | -- DIRE WARNING. |
|---|
| 219 | -- The OnStack case of sequelToAmode delivers an Amode which is only |
|---|
| 220 | -- valid just before the final control transfer, because it assumes |
|---|
| 221 | -- that Sp is pointing to the top word of the return address. This |
|---|
| 222 | -- seems unclean but there you go. |
|---|
| 223 | |
|---|
| 224 | getSequelAmode :: FCode CmmExpr |
|---|
| 225 | getSequelAmode |
|---|
| 226 | = do { EndOfBlockInfo virt_sp sequel <- getEndOfBlockInfo |
|---|
| 227 | ; case sequel of |
|---|
| 228 | OnStack -> do { sp_rel <- getSpRelOffset virt_sp |
|---|
| 229 | ; returnFC (CmmLoad sp_rel bWord) } |
|---|
| 230 | |
|---|
| 231 | CaseAlts lbl _ _ -> returnFC (CmmLit (CmmLabel lbl)) |
|---|
| 232 | } |
|---|
| 233 | |
|---|
| 234 | ------------------------------------------------------------------------- |
|---|
| 235 | -- |
|---|
| 236 | -- Register assignment |
|---|
| 237 | -- |
|---|
| 238 | ------------------------------------------------------------------------- |
|---|
| 239 | |
|---|
| 240 | -- How to assign registers for |
|---|
| 241 | -- |
|---|
| 242 | -- 1) Calling a fast entry point. |
|---|
| 243 | -- 2) Returning an unboxed tuple. |
|---|
| 244 | -- 3) Invoking an out-of-line PrimOp. |
|---|
| 245 | -- |
|---|
| 246 | -- Registers are assigned in order. |
|---|
| 247 | -- |
|---|
| 248 | -- If we run out, we don't attempt to assign any further registers (even |
|---|
| 249 | -- though we might have run out of only one kind of register); we just |
|---|
| 250 | -- return immediately with the left-overs specified. |
|---|
| 251 | -- |
|---|
| 252 | -- The alternative version @assignAllRegs@ uses the complete set of |
|---|
| 253 | -- registers, including those that aren't mapped to real machine |
|---|
| 254 | -- registers. This is used for calling special RTS functions and PrimOps |
|---|
| 255 | -- which expect their arguments to always be in the same registers. |
|---|
| 256 | |
|---|
| 257 | assignCallRegs, assignPrimOpCallRegs, assignReturnRegs |
|---|
| 258 | :: [(CgRep,a)] -- Arg or result values to assign |
|---|
| 259 | -> ([(a, GlobalReg)], -- Register assignment in same order |
|---|
| 260 | -- for *initial segment of* input list |
|---|
| 261 | -- (but reversed; doesn't matter) |
|---|
| 262 | -- VoidRep args do not appear here |
|---|
| 263 | [(CgRep,a)]) -- Leftover arg or result values |
|---|
| 264 | |
|---|
| 265 | assignCallRegs args |
|---|
| 266 | = assign_regs args (mkRegTbl [node]) |
|---|
| 267 | -- The entry convention for a function closure |
|---|
| 268 | -- never uses Node for argument passing; instead |
|---|
| 269 | -- Node points to the function closure itself |
|---|
| 270 | |
|---|
| 271 | assignPrimOpCallRegs args |
|---|
| 272 | = assign_regs args (mkRegTbl_allRegs []) |
|---|
| 273 | -- For primops, *all* arguments must be passed in registers |
|---|
| 274 | |
|---|
| 275 | assignReturnRegs args |
|---|
| 276 | -- when we have a single non-void component to return, use the normal |
|---|
| 277 | -- unpointed return convention. This make various things simpler: it |
|---|
| 278 | -- means we can assume a consistent convention for IO, which is useful |
|---|
| 279 | -- when writing code that relies on knowing the IO return convention in |
|---|
| 280 | -- the RTS (primops, especially exception-related primops). |
|---|
| 281 | -- Also, the bytecode compiler assumes this when compiling |
|---|
| 282 | -- case expressions and ccalls, so it only needs to know one set of |
|---|
| 283 | -- return conventions. |
|---|
| 284 | | [(rep,arg)] <- non_void_args, CmmGlobal r <- dataReturnConvPrim rep |
|---|
| 285 | = ([(arg, r)], []) |
|---|
| 286 | | otherwise |
|---|
| 287 | = assign_regs args (mkRegTbl []) |
|---|
| 288 | -- For returning unboxed tuples etc, |
|---|
| 289 | -- we use all regs |
|---|
| 290 | where |
|---|
| 291 | non_void_args = filter ((/= VoidArg).fst) args |
|---|
| 292 | |
|---|
| 293 | assign_regs :: [(CgRep,a)] -- Arg or result values to assign |
|---|
| 294 | -> AvailRegs -- Regs still avail: Vanilla, Float, Double, Longs |
|---|
| 295 | -> ([(a, GlobalReg)], [(CgRep, a)]) |
|---|
| 296 | assign_regs args supply |
|---|
| 297 | = go args [] supply |
|---|
| 298 | where |
|---|
| 299 | go [] acc _ = (acc, []) -- Return the results reversed (doesn't matter) |
|---|
| 300 | go ((VoidArg,_) : args) acc supply -- Skip void arguments; they aren't passed, and |
|---|
| 301 | = go args acc supply -- there's nothing to bind them to |
|---|
| 302 | go ((rep,arg) : args) acc supply |
|---|
| 303 | = case assign_reg rep supply of |
|---|
| 304 | Just (reg, supply') -> go args ((arg,reg):acc) supply' |
|---|
| 305 | Nothing -> (acc, (rep,arg):args) -- No more regs |
|---|
| 306 | |
|---|
| 307 | assign_reg :: CgRep -> AvailRegs -> Maybe (GlobalReg, AvailRegs) |
|---|
| 308 | assign_reg FloatArg (vs, f:fs, ds, ls) = Just (FloatReg f, (vs, fs, ds, ls)) |
|---|
| 309 | assign_reg DoubleArg (vs, fs, d:ds, ls) = Just (DoubleReg d, (vs, fs, ds, ls)) |
|---|
| 310 | assign_reg LongArg (vs, fs, ds, l:ls) = Just (LongReg l, (vs, fs, ds, ls)) |
|---|
| 311 | assign_reg PtrArg (v:vs, fs, ds, ls) = Just (VanillaReg v VGcPtr, (vs, fs, ds, ls)) |
|---|
| 312 | assign_reg NonPtrArg (v:vs, fs, ds, ls) = Just (VanillaReg v VNonGcPtr, (vs, fs, ds, ls)) |
|---|
| 313 | -- PtrArg and NonPtrArg both go in a vanilla register |
|---|
| 314 | assign_reg _ _ = Nothing |
|---|
| 315 | |
|---|
| 316 | |
|---|
| 317 | ------------------------------------------------------------------------- |
|---|
| 318 | -- |
|---|
| 319 | -- Register supplies |
|---|
| 320 | -- |
|---|
| 321 | ------------------------------------------------------------------------- |
|---|
| 322 | |
|---|
| 323 | -- Vanilla registers can contain pointers, Ints, Chars. |
|---|
| 324 | -- Floats and doubles have separate register supplies. |
|---|
| 325 | -- |
|---|
| 326 | -- We take these register supplies from the *real* registers, i.e. those |
|---|
| 327 | -- that are guaranteed to map to machine registers. |
|---|
| 328 | |
|---|
| 329 | useVanillaRegs :: Int |
|---|
| 330 | useVanillaRegs | opt_Unregisterised = 0 |
|---|
| 331 | | otherwise = mAX_Real_Vanilla_REG |
|---|
| 332 | useFloatRegs :: Int |
|---|
| 333 | useFloatRegs | opt_Unregisterised = 0 |
|---|
| 334 | | otherwise = mAX_Real_Float_REG |
|---|
| 335 | useDoubleRegs :: Int |
|---|
| 336 | useDoubleRegs | opt_Unregisterised = 0 |
|---|
| 337 | | otherwise = mAX_Real_Double_REG |
|---|
| 338 | useLongRegs :: Int |
|---|
| 339 | useLongRegs | opt_Unregisterised = 0 |
|---|
| 340 | | otherwise = mAX_Real_Long_REG |
|---|
| 341 | |
|---|
| 342 | vanillaRegNos, floatRegNos, doubleRegNos, longRegNos :: [Int] |
|---|
| 343 | vanillaRegNos = regList useVanillaRegs |
|---|
| 344 | floatRegNos = regList useFloatRegs |
|---|
| 345 | doubleRegNos = regList useDoubleRegs |
|---|
| 346 | longRegNos = regList useLongRegs |
|---|
| 347 | |
|---|
| 348 | allVanillaRegNos, allFloatRegNos, allDoubleRegNos, allLongRegNos :: [Int] |
|---|
| 349 | allVanillaRegNos = regList mAX_Vanilla_REG |
|---|
| 350 | allFloatRegNos = regList mAX_Float_REG |
|---|
| 351 | allDoubleRegNos = regList mAX_Double_REG |
|---|
| 352 | allLongRegNos = regList mAX_Long_REG |
|---|
| 353 | |
|---|
| 354 | regList :: Int -> [Int] |
|---|
| 355 | regList n = [1 .. n] |
|---|
| 356 | |
|---|
| 357 | type AvailRegs = ( [Int] -- available vanilla regs. |
|---|
| 358 | , [Int] -- floats |
|---|
| 359 | , [Int] -- doubles |
|---|
| 360 | , [Int] -- longs (int64 and word64) |
|---|
| 361 | ) |
|---|
| 362 | |
|---|
| 363 | mkRegTbl :: [GlobalReg] -> AvailRegs |
|---|
| 364 | mkRegTbl regs_in_use |
|---|
| 365 | = mkRegTbl' regs_in_use vanillaRegNos floatRegNos doubleRegNos longRegNos |
|---|
| 366 | |
|---|
| 367 | mkRegTbl_allRegs :: [GlobalReg] -> AvailRegs |
|---|
| 368 | mkRegTbl_allRegs regs_in_use |
|---|
| 369 | = mkRegTbl' regs_in_use allVanillaRegNos allFloatRegNos allDoubleRegNos allLongRegNos |
|---|
| 370 | |
|---|
| 371 | mkRegTbl' :: [GlobalReg] -> [Int] -> [Int] -> [Int] -> [Int] |
|---|
| 372 | -> ([Int], [Int], [Int], [Int]) |
|---|
| 373 | mkRegTbl' regs_in_use vanillas floats doubles longs |
|---|
| 374 | = (ok_vanilla, ok_float, ok_double, ok_long) |
|---|
| 375 | where |
|---|
| 376 | ok_vanilla = mapCatMaybes (select (\i -> VanillaReg i VNonGcPtr)) vanillas |
|---|
| 377 | -- ptrhood isn't looked at, hence we can use any old rep. |
|---|
| 378 | ok_float = mapCatMaybes (select FloatReg) floats |
|---|
| 379 | ok_double = mapCatMaybes (select DoubleReg) doubles |
|---|
| 380 | ok_long = mapCatMaybes (select LongReg) longs |
|---|
| 381 | |
|---|
| 382 | select :: (Int -> GlobalReg) -> Int{-cand-} -> Maybe Int |
|---|
| 383 | -- one we've unboxed the Int, we make a GlobalReg |
|---|
| 384 | -- and see if it is already in use; if not, return its number. |
|---|
| 385 | |
|---|
| 386 | select mk_reg_fun cand |
|---|
| 387 | = let |
|---|
| 388 | reg = mk_reg_fun cand |
|---|
| 389 | in |
|---|
| 390 | if reg `not_elem` regs_in_use |
|---|
| 391 | then Just cand |
|---|
| 392 | else Nothing |
|---|
| 393 | where |
|---|
| 394 | not_elem = isn'tIn "mkRegTbl" |
|---|
| 395 | |
|---|