{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}

-----------------------------------------------------------------------------
--
-- Building info tables.
--
-- (c) The University of Glasgow 2004-2006
--
-----------------------------------------------------------------------------

module GHC.StgToCmm.Layout (
        mkArgDescr,
        emitCall, emitReturn, adjustHpBackwards,

        emitClosureProcAndInfoTable,
        emitClosureAndInfoTable,

        slowCall, directCall,

        FieldOffOrPadding(..),
        ClosureHeader(..),
        mkVirtHeapOffsets,
        mkVirtHeapOffsetsWithPadding,
        mkVirtConstrOffsets,
        mkVirtConstrSizes,
        getHpRelOffset,

        ArgRep(..), toArgRep, argRepSizeW -- re-exported from GHC.StgToCmm.ArgRep
  ) where


#include "GhclibHsVersions.h"

import GHC.Prelude hiding ((<*>))

import GHC.StgToCmm.Closure
import GHC.StgToCmm.Env
import GHC.StgToCmm.ArgRep -- notably: ( slowCallPattern )
import GHC.StgToCmm.Ticky
import GHC.StgToCmm.Monad
import GHC.StgToCmm.Utils

import GHC.Cmm.Graph
import GHC.Runtime.Heap.Layout
import GHC.Cmm.BlockId
import GHC.Cmm
import GHC.Cmm.Utils
import GHC.Cmm.Info
import GHC.Cmm.CLabel
import GHC.Stg.Syntax
import GHC.Types.Id
import GHC.Core.TyCon    ( PrimRep(..), primRepSizeB )
import GHC.Types.Basic   ( RepArity )
import GHC.Driver.Session
import GHC.Platform
import GHC.Unit

import GHC.Utils.Misc
import Data.List
import GHC.Utils.Outputable
import GHC.Data.FastString
import Control.Monad

------------------------------------------------------------------------
--                Call and return sequences
------------------------------------------------------------------------

-- | Return multiple values to the sequel
--
-- If the sequel is @Return@
--
-- >     return (x,y)
--
-- If the sequel is @AssignTo [p,q]@
--
-- >    p=x; q=y;
--
emitReturn :: [CmmExpr] -> FCode ReturnKind
emitReturn :: [CmmExpr] -> FCode ReturnKind
emitReturn [CmmExpr]
results
  = do { DynFlags
dflags    <- FCode DynFlags
forall (m :: * -> *). HasDynFlags m => m DynFlags
getDynFlags
       ; Platform
platform  <- FCode Platform
getPlatform
       ; Sequel
sequel    <- FCode Sequel
getSequel
       ; UpdFrameOffset
updfr_off <- FCode UpdFrameOffset
getUpdFrameOff
       ; case Sequel
sequel of
           Sequel
Return ->
             do { FCode ()
adjustHpBackwards
                ; let e :: CmmExpr
e = CmmExpr -> CmmType -> CmmExpr
CmmLoad (Area -> UpdFrameOffset -> CmmExpr
CmmStackSlot Area
Old UpdFrameOffset
updfr_off) (Platform -> CmmType
gcWord Platform
platform)
                ; CmmAGraph -> FCode ()
emit (DynFlags -> CmmExpr -> [CmmExpr] -> UpdFrameOffset -> CmmAGraph
mkReturn DynFlags
dflags (Platform -> CmmExpr -> CmmExpr
entryCode Platform
platform CmmExpr
e) [CmmExpr]
results UpdFrameOffset
updfr_off)
                }
           AssignTo [LocalReg]
regs Bool
adjust ->
             do { Bool -> FCode () -> FCode ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
adjust FCode ()
adjustHpBackwards
                ; [LocalReg] -> [CmmExpr] -> FCode ()
emitMultiAssign  [LocalReg]
regs [CmmExpr]
results }
       ; ReturnKind -> FCode ReturnKind
forall (m :: * -> *) a. Monad m => a -> m a
return ReturnKind
AssignedDirectly
       }


-- | @emitCall conv fun args@ makes a call to the entry-code of @fun@,
-- using the call/return convention @conv@, passing @args@, and
-- returning the results to the current sequel.
--
emitCall :: (Convention, Convention) -> CmmExpr -> [CmmExpr] -> FCode ReturnKind
emitCall :: (Convention, Convention)
-> CmmExpr -> [CmmExpr] -> FCode ReturnKind
emitCall (Convention, Convention)
convs CmmExpr
fun [CmmExpr]
args
  = (Convention, Convention)
-> CmmExpr -> [CmmExpr] -> [CmmExpr] -> FCode ReturnKind
emitCallWithExtraStack (Convention, Convention)
convs CmmExpr
fun [CmmExpr]
args [CmmExpr]
noExtraStack


-- | @emitCallWithExtraStack conv fun args stack@ makes a call to the
-- entry-code of @fun@, using the call/return convention @conv@,
-- passing @args@, pushing some extra stack frames described by
-- @stack@, and returning the results to the current sequel.
--
emitCallWithExtraStack
   :: (Convention, Convention) -> CmmExpr -> [CmmExpr]
   -> [CmmExpr] -> FCode ReturnKind
emitCallWithExtraStack :: (Convention, Convention)
-> CmmExpr -> [CmmExpr] -> [CmmExpr] -> FCode ReturnKind
emitCallWithExtraStack (Convention
callConv, Convention
retConv) CmmExpr
fun [CmmExpr]
args [CmmExpr]
extra_stack
  = do  { DynFlags
dflags <- FCode DynFlags
forall (m :: * -> *). HasDynFlags m => m DynFlags
getDynFlags
        ; FCode ()
adjustHpBackwards
        ; Sequel
sequel <- FCode Sequel
getSequel
        ; UpdFrameOffset
updfr_off <- FCode UpdFrameOffset
getUpdFrameOff
        ; case Sequel
sequel of
            Sequel
Return -> do
              CmmAGraph -> FCode ()
emit (CmmAGraph -> FCode ()) -> CmmAGraph -> FCode ()
forall a b. (a -> b) -> a -> b
$ DynFlags
-> Convention
-> CmmExpr
-> [CmmExpr]
-> UpdFrameOffset
-> [CmmExpr]
-> CmmAGraph
mkJumpExtra DynFlags
dflags Convention
callConv CmmExpr
fun [CmmExpr]
args UpdFrameOffset
updfr_off [CmmExpr]
extra_stack
              ReturnKind -> FCode ReturnKind
forall (m :: * -> *) a. Monad m => a -> m a
return ReturnKind
AssignedDirectly
            AssignTo [LocalReg]
res_regs Bool
_ -> do
              BlockId
k <- FCode BlockId
forall (m :: * -> *). MonadUnique m => m BlockId
newBlockId
              let area :: Area
area = BlockId -> Area
Young BlockId
k
                  (UpdFrameOffset
off, [GlobalReg]
_, CmmAGraph
copyin) = DynFlags
-> Convention
-> Area
-> [LocalReg]
-> [LocalReg]
-> (UpdFrameOffset, [GlobalReg], CmmAGraph)
copyInOflow DynFlags
dflags Convention
retConv Area
area [LocalReg]
res_regs []
                  copyout :: CmmAGraph
copyout = DynFlags
-> CmmExpr
-> Convention
-> [CmmExpr]
-> BlockId
-> UpdFrameOffset
-> UpdFrameOffset
-> [CmmExpr]
-> CmmAGraph
mkCallReturnsTo DynFlags
dflags CmmExpr
fun Convention
callConv [CmmExpr]
args BlockId
k UpdFrameOffset
off UpdFrameOffset
updfr_off
                                   [CmmExpr]
extra_stack
              CmmTickScope
tscope <- FCode CmmTickScope
getTickScope
              CmmAGraph -> FCode ()
emit (CmmAGraph
copyout CmmAGraph -> CmmAGraph -> CmmAGraph
<*> BlockId -> CmmTickScope -> CmmAGraph
mkLabel BlockId
k CmmTickScope
tscope CmmAGraph -> CmmAGraph -> CmmAGraph
<*> CmmAGraph
copyin)
              ReturnKind -> FCode ReturnKind
forall (m :: * -> *) a. Monad m => a -> m a
return (BlockId -> UpdFrameOffset -> ReturnKind
ReturnedTo BlockId
k UpdFrameOffset
off)
      }


adjustHpBackwards :: FCode ()
-- This function adjusts the heap pointer just before a tail call or
-- return.  At a call or return, the virtual heap pointer may be less
-- than the real Hp, because the latter was advanced to deal with
-- the worst-case branch of the code, and we may be in a better-case
-- branch.  In that case, move the real Hp *back* and retract some
-- ticky allocation count.
--
-- It *does not* deal with high-water-mark adjustment.  That's done by
-- functions which allocate heap.
adjustHpBackwards :: FCode ()
adjustHpBackwards
  = do  { HeapUsage
hp_usg <- FCode HeapUsage
getHpUsage
        ; let rHp :: UpdFrameOffset
rHp = HeapUsage -> UpdFrameOffset
realHp HeapUsage
hp_usg
              vHp :: UpdFrameOffset
vHp = HeapUsage -> UpdFrameOffset
virtHp HeapUsage
hp_usg
              adjust_words :: UpdFrameOffset
adjust_words = UpdFrameOffset
vHp UpdFrameOffset -> UpdFrameOffset -> UpdFrameOffset
forall a. Num a => a -> a -> a
-UpdFrameOffset
rHp
        ; CmmExpr
new_hp <- UpdFrameOffset -> FCode CmmExpr
getHpRelOffset UpdFrameOffset
vHp

        ; CmmAGraph -> FCode ()
emit (if UpdFrameOffset
adjust_words UpdFrameOffset -> UpdFrameOffset -> Bool
forall a. Eq a => a -> a -> Bool
== UpdFrameOffset
0
                then CmmAGraph
mkNop
                else CmmReg -> CmmExpr -> CmmAGraph
mkAssign CmmReg
hpReg CmmExpr
new_hp) -- Generates nothing when vHp==rHp

        ; Bool -> UpdFrameOffset -> FCode ()
tickyAllocHeap Bool
False UpdFrameOffset
adjust_words -- ...ditto

        ; UpdFrameOffset -> FCode ()
setRealHp UpdFrameOffset
vHp
        }


-------------------------------------------------------------------------
--        Making calls: directCall and slowCall
-------------------------------------------------------------------------

-- General plan is:
--   - we'll make *one* fast call, either to the function itself
--     (directCall) or to stg_ap_<pat>_fast (slowCall)
--     Any left-over arguments will be pushed on the stack,
--
--     e.g. Sp[old+8]  = arg1
--          Sp[old+16] = arg2
--          Sp[old+32] = stg_ap_pp_info
--          R2 = arg3
--          R3 = arg4
--          call f() return to Nothing updfr_off: 32


directCall :: Convention -> CLabel -> RepArity -> [StgArg] -> FCode ReturnKind
-- (directCall f n args)
-- calls f(arg1, ..., argn), and applies the result to the remaining args
-- The function f has arity n, and there are guaranteed at least n args
-- Both arity and args include void args
directCall :: Convention
-> CLabel -> UpdFrameOffset -> [StgArg] -> FCode ReturnKind
directCall Convention
conv CLabel
lbl UpdFrameOffset
arity [StgArg]
stg_args
  = do  { [(ArgRep, Maybe CmmExpr)]
argreps <- [StgArg] -> FCode [(ArgRep, Maybe CmmExpr)]
getArgRepsAmodes [StgArg]
stg_args
        ; String
-> Convention
-> CLabel
-> UpdFrameOffset
-> [(ArgRep, Maybe CmmExpr)]
-> FCode ReturnKind
direct_call String
"directCall" Convention
conv CLabel
lbl UpdFrameOffset
arity [(ArgRep, Maybe CmmExpr)]
argreps }


slowCall :: CmmExpr -> [StgArg] -> FCode ReturnKind
-- (slowCall fun args) applies fun to args, returning the results to Sequel
slowCall :: CmmExpr -> [StgArg] -> FCode ReturnKind
slowCall CmmExpr
fun [StgArg]
stg_args
  = do  DynFlags
dflags <- FCode DynFlags
forall (m :: * -> *). HasDynFlags m => m DynFlags
getDynFlags
        Platform
platform <- FCode Platform
getPlatform
        [(ArgRep, Maybe CmmExpr)]
argsreps <- [StgArg] -> FCode [(ArgRep, Maybe CmmExpr)]
getArgRepsAmodes [StgArg]
stg_args
        let (FastString
rts_fun, UpdFrameOffset
arity) = [ArgRep] -> (FastString, UpdFrameOffset)
slowCallPattern (((ArgRep, Maybe CmmExpr) -> ArgRep)
-> [(ArgRep, Maybe CmmExpr)] -> [ArgRep]
forall a b. (a -> b) -> [a] -> [b]
map (ArgRep, Maybe CmmExpr) -> ArgRep
forall a b. (a, b) -> a
fst [(ArgRep, Maybe CmmExpr)]
argsreps)

        (ReturnKind
r, CmmAGraph
slow_code) <- FCode ReturnKind -> FCode (ReturnKind, CmmAGraph)
forall a. FCode a -> FCode (a, CmmAGraph)
getCodeR (FCode ReturnKind -> FCode (ReturnKind, CmmAGraph))
-> FCode ReturnKind -> FCode (ReturnKind, CmmAGraph)
forall a b. (a -> b) -> a -> b
$ do
           ReturnKind
r <- String
-> Convention
-> CLabel
-> UpdFrameOffset
-> [(ArgRep, Maybe CmmExpr)]
-> FCode ReturnKind
direct_call String
"slow_call" Convention
NativeNodeCall
                 (FastString -> CLabel
mkRtsApFastLabel FastString
rts_fun) UpdFrameOffset
arity ((ArgRep
P,CmmExpr -> Maybe CmmExpr
forall a. a -> Maybe a
Just CmmExpr
fun)(ArgRep, Maybe CmmExpr)
-> [(ArgRep, Maybe CmmExpr)] -> [(ArgRep, Maybe CmmExpr)]
forall a. a -> [a] -> [a]
:[(ArgRep, Maybe CmmExpr)]
argsreps)
           FastString -> FCode ()
emitComment (FastString -> FCode ()) -> FastString -> FCode ()
forall a b. (a -> b) -> a -> b
$ String -> FastString
mkFastString (String
"slow_call for " String -> String -> String
forall a. [a] -> [a] -> [a]
++
                                      DynFlags -> SDoc -> String
showSDoc DynFlags
dflags (CmmExpr -> SDoc
forall a. Outputable a => a -> SDoc
ppr CmmExpr
fun) String -> String -> String
forall a. [a] -> [a] -> [a]
++
                                      String
" with pat " String -> String -> String
forall a. [a] -> [a] -> [a]
++ FastString -> String
unpackFS FastString
rts_fun)
           ReturnKind -> FCode ReturnKind
forall (m :: * -> *) a. Monad m => a -> m a
return ReturnKind
r

        -- Note [avoid intermediate PAPs]
        let n_args :: UpdFrameOffset
n_args = [StgArg] -> UpdFrameOffset
forall (t :: * -> *) a. Foldable t => t a -> UpdFrameOffset
length [StgArg]
stg_args
        if UpdFrameOffset
n_args UpdFrameOffset -> UpdFrameOffset -> Bool
forall a. Ord a => a -> a -> Bool
> UpdFrameOffset
arity Bool -> Bool -> Bool
&& DynFlags -> UpdFrameOffset
optLevel DynFlags
dflags UpdFrameOffset -> UpdFrameOffset -> Bool
forall a. Ord a => a -> a -> Bool
>= UpdFrameOffset
2
           then do
             CmmExpr
funv <- (CmmReg -> CmmExpr
CmmReg (CmmReg -> CmmExpr) -> (LocalReg -> CmmReg) -> LocalReg -> CmmExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LocalReg -> CmmReg
CmmLocal) (LocalReg -> CmmExpr) -> FCode LocalReg -> FCode CmmExpr
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` CmmExpr -> FCode LocalReg
assignTemp CmmExpr
fun
             CmmExpr
fun_iptr <- (CmmReg -> CmmExpr
CmmReg (CmmReg -> CmmExpr) -> (LocalReg -> CmmReg) -> LocalReg -> CmmExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LocalReg -> CmmReg
CmmLocal) (LocalReg -> CmmExpr) -> FCode LocalReg -> FCode CmmExpr
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap`
                    CmmExpr -> FCode LocalReg
assignTemp (DynFlags -> CmmExpr -> CmmExpr
closureInfoPtr DynFlags
dflags (DynFlags -> CmmExpr -> CmmExpr
cmmUntag DynFlags
dflags CmmExpr
funv))

             -- ToDo: we could do slightly better here by reusing the
             -- continuation from the slow call, which we have in r.
             -- Also we'd like to push the continuation on the stack
             -- before the branch, so that we only get one copy of the
             -- code that saves all the live variables across the
             -- call, but that might need some improvements to the
             -- special case in the stack layout code to handle this
             -- (see Note [diamond proc point]).

             CmmAGraph
fast_code <- FCode ReturnKind -> FCode CmmAGraph
forall a. FCode a -> FCode CmmAGraph
getCode (FCode ReturnKind -> FCode CmmAGraph)
-> FCode ReturnKind -> FCode CmmAGraph
forall a b. (a -> b) -> a -> b
$
                (Convention, Convention)
-> CmmExpr -> [CmmExpr] -> FCode ReturnKind
emitCall (Convention
NativeNodeCall, Convention
NativeReturn)
                  (Platform -> CmmExpr -> CmmExpr
entryCode Platform
platform CmmExpr
fun_iptr)
                  ([(ArgRep, Maybe CmmExpr)] -> [CmmExpr]
nonVArgs ((ArgRep
P,CmmExpr -> Maybe CmmExpr
forall a. a -> Maybe a
Just CmmExpr
funv)(ArgRep, Maybe CmmExpr)
-> [(ArgRep, Maybe CmmExpr)] -> [(ArgRep, Maybe CmmExpr)]
forall a. a -> [a] -> [a]
:[(ArgRep, Maybe CmmExpr)]
argsreps))

             BlockId
slow_lbl <- FCode BlockId
forall (m :: * -> *). MonadUnique m => m BlockId
newBlockId
             BlockId
fast_lbl <- FCode BlockId
forall (m :: * -> *). MonadUnique m => m BlockId
newBlockId
             BlockId
is_tagged_lbl <- FCode BlockId
forall (m :: * -> *). MonadUnique m => m BlockId
newBlockId
             BlockId
end_lbl <- FCode BlockId
forall (m :: * -> *). MonadUnique m => m BlockId
newBlockId

             let correct_arity :: CmmExpr
correct_arity = Platform -> CmmExpr -> CmmExpr -> CmmExpr
cmmEqWord Platform
platform (DynFlags -> CmmExpr -> CmmExpr
funInfoArity DynFlags
dflags CmmExpr
fun_iptr)
                                                    (Platform -> UpdFrameOffset -> CmmExpr
mkIntExpr Platform
platform UpdFrameOffset
n_args)

             CmmTickScope
tscope <- FCode CmmTickScope
getTickScope
             CmmAGraph -> FCode ()
emit (CmmExpr -> BlockId -> BlockId -> Maybe Bool -> CmmAGraph
mkCbranch (DynFlags -> CmmExpr -> CmmExpr
cmmIsTagged DynFlags
dflags CmmExpr
funv)
                             BlockId
is_tagged_lbl BlockId
slow_lbl (Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True)
                   CmmAGraph -> CmmAGraph -> CmmAGraph
<*> BlockId -> CmmTickScope -> CmmAGraph
mkLabel BlockId
is_tagged_lbl CmmTickScope
tscope
                   CmmAGraph -> CmmAGraph -> CmmAGraph
<*> CmmExpr -> BlockId -> BlockId -> Maybe Bool -> CmmAGraph
mkCbranch CmmExpr
correct_arity BlockId
fast_lbl BlockId
slow_lbl (Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True)
                   CmmAGraph -> CmmAGraph -> CmmAGraph
<*> BlockId -> CmmTickScope -> CmmAGraph
mkLabel BlockId
fast_lbl CmmTickScope
tscope
                   CmmAGraph -> CmmAGraph -> CmmAGraph
<*> CmmAGraph
fast_code
                   CmmAGraph -> CmmAGraph -> CmmAGraph
<*> BlockId -> CmmAGraph
mkBranch BlockId
end_lbl
                   CmmAGraph -> CmmAGraph -> CmmAGraph
<*> BlockId -> CmmTickScope -> CmmAGraph
mkLabel BlockId
slow_lbl CmmTickScope
tscope
                   CmmAGraph -> CmmAGraph -> CmmAGraph
<*> CmmAGraph
slow_code
                   CmmAGraph -> CmmAGraph -> CmmAGraph
<*> BlockId -> CmmTickScope -> CmmAGraph
mkLabel BlockId
end_lbl CmmTickScope
tscope)
             ReturnKind -> FCode ReturnKind
forall (m :: * -> *) a. Monad m => a -> m a
return ReturnKind
r

           else do
             CmmAGraph -> FCode ()
emit CmmAGraph
slow_code
             ReturnKind -> FCode ReturnKind
forall (m :: * -> *) a. Monad m => a -> m a
return ReturnKind
r


-- Note [avoid intermediate PAPs]
--
-- A slow call which needs multiple generic apply patterns will be
-- almost guaranteed to create one or more intermediate PAPs when
-- applied to a function that takes the correct number of arguments.
-- We try to avoid this situation by generating code to test whether
-- we are calling a function with the correct number of arguments
-- first, i.e.:
--
--   if (TAG(f) != 0} {  // f is not a thunk
--      if (f->info.arity == n) {
--         ... make a fast call to f ...
--      }
--   }
--   ... otherwise make the slow call ...
--
-- We *only* do this when the call requires multiple generic apply
-- functions, which requires pushing extra stack frames and probably
-- results in intermediate PAPs.  (I say probably, because it might be
-- that we're over-applying a function, but that seems even less
-- likely).
--
-- This very rarely applies, but if it does happen in an inner loop it
-- can have a severe impact on performance (#6084).


--------------
direct_call :: String
            -> Convention     -- e.g. NativeNodeCall or NativeDirectCall
            -> CLabel -> RepArity
            -> [(ArgRep,Maybe CmmExpr)] -> FCode ReturnKind
direct_call :: String
-> Convention
-> CLabel
-> UpdFrameOffset
-> [(ArgRep, Maybe CmmExpr)]
-> FCode ReturnKind
direct_call String
caller Convention
call_conv CLabel
lbl UpdFrameOffset
arity [(ArgRep, Maybe CmmExpr)]
args
  | Bool
debugIsOn Bool -> Bool -> Bool
&& [(ArgRep, Maybe CmmExpr)]
args [(ArgRep, Maybe CmmExpr)] -> UpdFrameOffset -> Bool
forall a. [a] -> UpdFrameOffset -> Bool
`lengthLessThan` UpdFrameOffset
real_arity  -- Too few args
  = do -- Caller should ensure that there enough args!
       String -> SDoc -> FCode ReturnKind
forall a. HasCallStack => String -> SDoc -> a
pprPanic String
"direct_call" (SDoc -> FCode ReturnKind) -> SDoc -> FCode ReturnKind
forall a b. (a -> b) -> a -> b
$
            String -> SDoc
text String
caller SDoc -> SDoc -> SDoc
<+> UpdFrameOffset -> SDoc
forall a. Outputable a => a -> SDoc
ppr UpdFrameOffset
arity SDoc -> SDoc -> SDoc
<+>
            CLabel -> SDoc
forall a. Outputable a => a -> SDoc
ppr CLabel
lbl SDoc -> SDoc -> SDoc
<+> UpdFrameOffset -> SDoc
forall a. Outputable a => a -> SDoc
ppr ([(ArgRep, Maybe CmmExpr)] -> UpdFrameOffset
forall (t :: * -> *) a. Foldable t => t a -> UpdFrameOffset
length [(ArgRep, Maybe CmmExpr)]
args) SDoc -> SDoc -> SDoc
<+>
            [Maybe CmmExpr] -> SDoc
forall a. Outputable a => a -> SDoc
ppr (((ArgRep, Maybe CmmExpr) -> Maybe CmmExpr)
-> [(ArgRep, Maybe CmmExpr)] -> [Maybe CmmExpr]
forall a b. (a -> b) -> [a] -> [b]
map (ArgRep, Maybe CmmExpr) -> Maybe CmmExpr
forall a b. (a, b) -> b
snd [(ArgRep, Maybe CmmExpr)]
args) SDoc -> SDoc -> SDoc
<+> [ArgRep] -> SDoc
forall a. Outputable a => a -> SDoc
ppr (((ArgRep, Maybe CmmExpr) -> ArgRep)
-> [(ArgRep, Maybe CmmExpr)] -> [ArgRep]
forall a b. (a -> b) -> [a] -> [b]
map (ArgRep, Maybe CmmExpr) -> ArgRep
forall a b. (a, b) -> a
fst [(ArgRep, Maybe CmmExpr)]
args)

  | [(ArgRep, Maybe CmmExpr)] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(ArgRep, Maybe CmmExpr)]
rest_args  -- Precisely the right number of arguments
  = (Convention, Convention)
-> CmmExpr -> [CmmExpr] -> FCode ReturnKind
emitCall (Convention
call_conv, Convention
NativeReturn) CmmExpr
target ([(ArgRep, Maybe CmmExpr)] -> [CmmExpr]
nonVArgs [(ArgRep, Maybe CmmExpr)]
args)

  | Bool
otherwise       -- Note [over-saturated calls]
  = do DynFlags
dflags <- FCode DynFlags
forall (m :: * -> *). HasDynFlags m => m DynFlags
getDynFlags
       (Convention, Convention)
-> CmmExpr -> [CmmExpr] -> [CmmExpr] -> FCode ReturnKind
emitCallWithExtraStack (Convention
call_conv, Convention
NativeReturn)
                              CmmExpr
target
                              ([(ArgRep, Maybe CmmExpr)] -> [CmmExpr]
nonVArgs [(ArgRep, Maybe CmmExpr)]
fast_args)
                              ([(ArgRep, Maybe CmmExpr)] -> [CmmExpr]
nonVArgs (DynFlags -> [(ArgRep, Maybe CmmExpr)]
stack_args DynFlags
dflags))
  where
    target :: CmmExpr
target = CmmLit -> CmmExpr
CmmLit (CLabel -> CmmLit
CmmLabel CLabel
lbl)
    ([(ArgRep, Maybe CmmExpr)]
fast_args, [(ArgRep, Maybe CmmExpr)]
rest_args) = UpdFrameOffset
-> [(ArgRep, Maybe CmmExpr)]
-> ([(ArgRep, Maybe CmmExpr)], [(ArgRep, Maybe CmmExpr)])
forall a. UpdFrameOffset -> [a] -> ([a], [a])
splitAt UpdFrameOffset
real_arity [(ArgRep, Maybe CmmExpr)]
args
    stack_args :: DynFlags -> [(ArgRep, Maybe CmmExpr)]
stack_args DynFlags
dflags = DynFlags -> [(ArgRep, Maybe CmmExpr)] -> [(ArgRep, Maybe CmmExpr)]
slowArgs DynFlags
dflags [(ArgRep, Maybe CmmExpr)]
rest_args
    real_arity :: UpdFrameOffset
real_arity = case Convention
call_conv of
                   Convention
NativeNodeCall -> UpdFrameOffset
arityUpdFrameOffset -> UpdFrameOffset -> UpdFrameOffset
forall a. Num a => a -> a -> a
+UpdFrameOffset
1
                   Convention
_              -> UpdFrameOffset
arity


-- When constructing calls, it is easier to keep the ArgReps and the
-- CmmExprs zipped together.  However, a void argument has no
-- representation, so we need to use Maybe CmmExpr (the alternative of
-- using zeroCLit or even undefined would work, but would be ugly).
--
getArgRepsAmodes :: [StgArg] -> FCode [(ArgRep, Maybe CmmExpr)]
getArgRepsAmodes :: [StgArg] -> FCode [(ArgRep, Maybe CmmExpr)]
getArgRepsAmodes = (StgArg -> FCode (ArgRep, Maybe CmmExpr))
-> [StgArg] -> FCode [(ArgRep, Maybe CmmExpr)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM StgArg -> FCode (ArgRep, Maybe CmmExpr)
getArgRepAmode
  where getArgRepAmode :: StgArg -> FCode (ArgRep, Maybe CmmExpr)
getArgRepAmode StgArg
arg
           | ArgRep
V <- ArgRep
rep  = (ArgRep, Maybe CmmExpr) -> FCode (ArgRep, Maybe CmmExpr)
forall (m :: * -> *) a. Monad m => a -> m a
return (ArgRep
V, Maybe CmmExpr
forall a. Maybe a
Nothing)
           | Bool
otherwise = do CmmExpr
expr <- NonVoid StgArg -> FCode CmmExpr
getArgAmode (StgArg -> NonVoid StgArg
forall a. a -> NonVoid a
NonVoid StgArg
arg)
                            (ArgRep, Maybe CmmExpr) -> FCode (ArgRep, Maybe CmmExpr)
forall (m :: * -> *) a. Monad m => a -> m a
return (ArgRep
rep, CmmExpr -> Maybe CmmExpr
forall a. a -> Maybe a
Just CmmExpr
expr)
           where rep :: ArgRep
rep = PrimRep -> ArgRep
toArgRep (StgArg -> PrimRep
argPrimRep StgArg
arg)

nonVArgs :: [(ArgRep, Maybe CmmExpr)] -> [CmmExpr]
nonVArgs :: [(ArgRep, Maybe CmmExpr)] -> [CmmExpr]
nonVArgs [] = []
nonVArgs ((ArgRep
_,Maybe CmmExpr
Nothing)  : [(ArgRep, Maybe CmmExpr)]
args) = [(ArgRep, Maybe CmmExpr)] -> [CmmExpr]
nonVArgs [(ArgRep, Maybe CmmExpr)]
args
nonVArgs ((ArgRep
_,Just CmmExpr
arg) : [(ArgRep, Maybe CmmExpr)]
args) = CmmExpr
arg CmmExpr -> [CmmExpr] -> [CmmExpr]
forall a. a -> [a] -> [a]
: [(ArgRep, Maybe CmmExpr)] -> [CmmExpr]
nonVArgs [(ArgRep, Maybe CmmExpr)]
args

{-
Note [over-saturated calls]

The natural thing to do for an over-saturated call would be to call
the function with the correct number of arguments, and then apply the
remaining arguments to the value returned, e.g.

  f a b c d   (where f has arity 2)
  -->
  r = call f(a,b)
  call r(c,d)

but this entails
  - saving c and d on the stack
  - making a continuation info table
  - at the continuation, loading c and d off the stack into regs
  - finally, call r

Note that since there are a fixed number of different r's
(e.g.  stg_ap_pp_fast), we can also pre-compile continuations
that correspond to each of them, rather than generating a fresh
one for each over-saturated call.

Not only does this generate much less code, it is faster too.  We will
generate something like:

Sp[old+16] = c
Sp[old+24] = d
Sp[old+32] = stg_ap_pp_info
call f(a,b) -- usual calling convention

For the purposes of the CmmCall node, we count this extra stack as
just more arguments that we are passing on the stack (cml_args).
-}

-- | 'slowArgs' takes a list of function arguments and prepares them for
-- pushing on the stack for "extra" arguments to a function which requires
-- fewer arguments than we currently have.
slowArgs :: DynFlags -> [(ArgRep, Maybe CmmExpr)] -> [(ArgRep, Maybe CmmExpr)]
slowArgs :: DynFlags -> [(ArgRep, Maybe CmmExpr)] -> [(ArgRep, Maybe CmmExpr)]
slowArgs DynFlags
_ [] = []
slowArgs DynFlags
dflags [(ArgRep, Maybe CmmExpr)]
args -- careful: reps contains voids (V), but args does not
  | DynFlags -> Bool
sccProfilingEnabled DynFlags
dflags
              = [(ArgRep, Maybe CmmExpr)]
save_cccs [(ArgRep, Maybe CmmExpr)]
-> [(ArgRep, Maybe CmmExpr)] -> [(ArgRep, Maybe CmmExpr)]
forall a. [a] -> [a] -> [a]
++ [(ArgRep, Maybe CmmExpr)]
this_pat [(ArgRep, Maybe CmmExpr)]
-> [(ArgRep, Maybe CmmExpr)] -> [(ArgRep, Maybe CmmExpr)]
forall a. [a] -> [a] -> [a]
++ DynFlags -> [(ArgRep, Maybe CmmExpr)] -> [(ArgRep, Maybe CmmExpr)]
slowArgs DynFlags
dflags [(ArgRep, Maybe CmmExpr)]
rest_args
  | Bool
otherwise =              [(ArgRep, Maybe CmmExpr)]
this_pat [(ArgRep, Maybe CmmExpr)]
-> [(ArgRep, Maybe CmmExpr)] -> [(ArgRep, Maybe CmmExpr)]
forall a. [a] -> [a] -> [a]
++ DynFlags -> [(ArgRep, Maybe CmmExpr)] -> [(ArgRep, Maybe CmmExpr)]
slowArgs DynFlags
dflags [(ArgRep, Maybe CmmExpr)]
rest_args
  where
    (FastString
arg_pat, UpdFrameOffset
n)            = [ArgRep] -> (FastString, UpdFrameOffset)
slowCallPattern (((ArgRep, Maybe CmmExpr) -> ArgRep)
-> [(ArgRep, Maybe CmmExpr)] -> [ArgRep]
forall a b. (a -> b) -> [a] -> [b]
map (ArgRep, Maybe CmmExpr) -> ArgRep
forall a b. (a, b) -> a
fst [(ArgRep, Maybe CmmExpr)]
args)
    ([(ArgRep, Maybe CmmExpr)]
call_args, [(ArgRep, Maybe CmmExpr)]
rest_args)  = UpdFrameOffset
-> [(ArgRep, Maybe CmmExpr)]
-> ([(ArgRep, Maybe CmmExpr)], [(ArgRep, Maybe CmmExpr)])
forall a. UpdFrameOffset -> [a] -> ([a], [a])
splitAt UpdFrameOffset
n [(ArgRep, Maybe CmmExpr)]
args

    stg_ap_pat :: CLabel
stg_ap_pat = UnitId -> FastString -> CLabel
mkCmmRetInfoLabel UnitId
rtsUnitId FastString
arg_pat
    this_pat :: [(ArgRep, Maybe CmmExpr)]
this_pat   = (ArgRep
N, CmmExpr -> Maybe CmmExpr
forall a. a -> Maybe a
Just (CLabel -> CmmExpr
mkLblExpr CLabel
stg_ap_pat)) (ArgRep, Maybe CmmExpr)
-> [(ArgRep, Maybe CmmExpr)] -> [(ArgRep, Maybe CmmExpr)]
forall a. a -> [a] -> [a]
: [(ArgRep, Maybe CmmExpr)]
call_args
    save_cccs :: [(ArgRep, Maybe CmmExpr)]
save_cccs  = [(ArgRep
N, CmmExpr -> Maybe CmmExpr
forall a. a -> Maybe a
Just (CLabel -> CmmExpr
mkLblExpr CLabel
save_cccs_lbl)), (ArgRep
N, CmmExpr -> Maybe CmmExpr
forall a. a -> Maybe a
Just CmmExpr
cccsExpr)]
    save_cccs_lbl :: CLabel
save_cccs_lbl = UnitId -> FastString -> CLabel
mkCmmRetInfoLabel UnitId
rtsUnitId (String -> FastString
fsLit String
"stg_restore_cccs")

-------------------------------------------------------------------------
----        Laying out objects on the heap and stack
-------------------------------------------------------------------------

-- The heap always grows upwards, so hpRel is easy to compute
hpRel :: VirtualHpOffset         -- virtual offset of Hp
      -> VirtualHpOffset         -- virtual offset of The Thing
      -> WordOff                -- integer word offset
hpRel :: UpdFrameOffset -> UpdFrameOffset -> UpdFrameOffset
hpRel UpdFrameOffset
hp UpdFrameOffset
off = UpdFrameOffset
off UpdFrameOffset -> UpdFrameOffset -> UpdFrameOffset
forall a. Num a => a -> a -> a
- UpdFrameOffset
hp

getHpRelOffset :: VirtualHpOffset -> FCode CmmExpr
-- See Note [Virtual and real heap pointers] in GHC.StgToCmm.Monad
getHpRelOffset :: UpdFrameOffset -> FCode CmmExpr
getHpRelOffset UpdFrameOffset
virtual_offset
  = do Platform
platform <- FCode Platform
getPlatform
       HeapUsage
hp_usg <- FCode HeapUsage
getHpUsage
       CmmExpr -> FCode CmmExpr
forall (m :: * -> *) a. Monad m => a -> m a
return (Platform -> CmmReg -> UpdFrameOffset -> CmmExpr
cmmRegOffW Platform
platform CmmReg
hpReg (UpdFrameOffset -> UpdFrameOffset -> UpdFrameOffset
hpRel (HeapUsage -> UpdFrameOffset
realHp HeapUsage
hp_usg) UpdFrameOffset
virtual_offset))

data FieldOffOrPadding a
    = FieldOff (NonVoid a) -- Something that needs an offset.
               ByteOff     -- Offset in bytes.
    | Padding ByteOff  -- Length of padding in bytes.
              ByteOff  -- Offset in bytes.

-- | Used to tell the various @mkVirtHeapOffsets@ functions what kind
-- of header the object has.  This will be accounted for in the
-- offsets of the fields returned.
data ClosureHeader
  = NoHeader
  | StdHeader
  | ThunkHeader

mkVirtHeapOffsetsWithPadding
  :: DynFlags
  -> ClosureHeader            -- What kind of header to account for
  -> [NonVoid (PrimRep, a)]   -- Things to make offsets for
  -> ( WordOff                -- Total number of words allocated
     , WordOff                -- Number of words allocated for *pointers*
     , [FieldOffOrPadding a]  -- Either an offset or padding.
     )

-- Things with their offsets from start of object in order of
-- increasing offset; BUT THIS MAY BE DIFFERENT TO INPUT ORDER
-- First in list gets lowest offset, which is initial offset + 1.
--
-- mkVirtHeapOffsetsWithPadding always returns boxed things with smaller offsets
-- than the unboxed things

mkVirtHeapOffsetsWithPadding :: DynFlags
-> ClosureHeader
-> [NonVoid (PrimRep, a)]
-> (UpdFrameOffset, UpdFrameOffset, [FieldOffOrPadding a])
mkVirtHeapOffsetsWithPadding DynFlags
dflags ClosureHeader
header [NonVoid (PrimRep, a)]
things =
    ASSERT(not (any (isVoidRep . fst . fromNonVoid) things))
    ( UpdFrameOffset
tot_wds
    , Platform -> UpdFrameOffset -> UpdFrameOffset
bytesToWordsRoundUp Platform
platform UpdFrameOffset
bytes_of_ptrs
    , [[FieldOffOrPadding a]] -> [FieldOffOrPadding a]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[FieldOffOrPadding a]]
ptrs_w_offsets [[FieldOffOrPadding a]]
-> [[FieldOffOrPadding a]] -> [[FieldOffOrPadding a]]
forall a. [a] -> [a] -> [a]
++ [[FieldOffOrPadding a]]
non_ptrs_w_offsets) [FieldOffOrPadding a]
-> [FieldOffOrPadding a] -> [FieldOffOrPadding a]
forall a. [a] -> [a] -> [a]
++ [FieldOffOrPadding a]
forall a. [FieldOffOrPadding a]
final_pad
    )
  where
    platform :: Platform
platform = DynFlags -> Platform
targetPlatform DynFlags
dflags
    hdr_words :: UpdFrameOffset
hdr_words = case ClosureHeader
header of
      ClosureHeader
NoHeader -> UpdFrameOffset
0
      ClosureHeader
StdHeader -> DynFlags -> UpdFrameOffset
fixedHdrSizeW DynFlags
dflags
      ClosureHeader
ThunkHeader -> DynFlags -> UpdFrameOffset
thunkHdrSize DynFlags
dflags
    hdr_bytes :: UpdFrameOffset
hdr_bytes = Platform -> UpdFrameOffset -> UpdFrameOffset
forall a. Num a => Platform -> a -> a
wordsToBytes Platform
platform UpdFrameOffset
hdr_words

    ([NonVoid (PrimRep, a)]
ptrs, [NonVoid (PrimRep, a)]
non_ptrs) = (NonVoid (PrimRep, a) -> Bool)
-> [NonVoid (PrimRep, a)]
-> ([NonVoid (PrimRep, a)], [NonVoid (PrimRep, a)])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition (PrimRep -> Bool
isGcPtrRep (PrimRep -> Bool)
-> (NonVoid (PrimRep, a) -> PrimRep)
-> NonVoid (PrimRep, a)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (PrimRep, a) -> PrimRep
forall a b. (a, b) -> a
fst ((PrimRep, a) -> PrimRep)
-> (NonVoid (PrimRep, a) -> (PrimRep, a))
-> NonVoid (PrimRep, a)
-> PrimRep
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonVoid (PrimRep, a) -> (PrimRep, a)
forall a. NonVoid a -> a
fromNonVoid) [NonVoid (PrimRep, a)]
things

    (UpdFrameOffset
bytes_of_ptrs, [[FieldOffOrPadding a]]
ptrs_w_offsets) =
       (UpdFrameOffset
 -> NonVoid (PrimRep, a) -> (UpdFrameOffset, [FieldOffOrPadding a]))
-> UpdFrameOffset
-> [NonVoid (PrimRep, a)]
-> (UpdFrameOffset, [[FieldOffOrPadding a]])
forall (t :: * -> *) a b c.
Traversable t =>
(a -> b -> (a, c)) -> a -> t b -> (a, t c)
mapAccumL UpdFrameOffset
-> NonVoid (PrimRep, a) -> (UpdFrameOffset, [FieldOffOrPadding a])
forall a.
UpdFrameOffset
-> NonVoid (PrimRep, a) -> (UpdFrameOffset, [FieldOffOrPadding a])
computeOffset UpdFrameOffset
0 [NonVoid (PrimRep, a)]
ptrs
    (UpdFrameOffset
tot_bytes, [[FieldOffOrPadding a]]
non_ptrs_w_offsets) =
       (UpdFrameOffset
 -> NonVoid (PrimRep, a) -> (UpdFrameOffset, [FieldOffOrPadding a]))
-> UpdFrameOffset
-> [NonVoid (PrimRep, a)]
-> (UpdFrameOffset, [[FieldOffOrPadding a]])
forall (t :: * -> *) a b c.
Traversable t =>
(a -> b -> (a, c)) -> a -> t b -> (a, t c)
mapAccumL UpdFrameOffset
-> NonVoid (PrimRep, a) -> (UpdFrameOffset, [FieldOffOrPadding a])
forall a.
UpdFrameOffset
-> NonVoid (PrimRep, a) -> (UpdFrameOffset, [FieldOffOrPadding a])
computeOffset UpdFrameOffset
bytes_of_ptrs [NonVoid (PrimRep, a)]
non_ptrs

    tot_wds :: UpdFrameOffset
tot_wds = Platform -> UpdFrameOffset -> UpdFrameOffset
bytesToWordsRoundUp Platform
platform UpdFrameOffset
tot_bytes

    final_pad_size :: UpdFrameOffset
final_pad_size = UpdFrameOffset
tot_wds UpdFrameOffset -> UpdFrameOffset -> UpdFrameOffset
forall a. Num a => a -> a -> a
* UpdFrameOffset
word_size UpdFrameOffset -> UpdFrameOffset -> UpdFrameOffset
forall a. Num a => a -> a -> a
- UpdFrameOffset
tot_bytes
    final_pad :: [FieldOffOrPadding a]
final_pad
        | UpdFrameOffset
final_pad_size UpdFrameOffset -> UpdFrameOffset -> Bool
forall a. Ord a => a -> a -> Bool
> UpdFrameOffset
0 = [(UpdFrameOffset -> UpdFrameOffset -> FieldOffOrPadding a
forall a. UpdFrameOffset -> UpdFrameOffset -> FieldOffOrPadding a
Padding UpdFrameOffset
final_pad_size
                                         (UpdFrameOffset
hdr_bytes UpdFrameOffset -> UpdFrameOffset -> UpdFrameOffset
forall a. Num a => a -> a -> a
+ UpdFrameOffset
tot_bytes))]
        | Bool
otherwise          = []

    word_size :: UpdFrameOffset
word_size = Platform -> UpdFrameOffset
platformWordSizeInBytes Platform
platform

    computeOffset :: UpdFrameOffset
-> NonVoid (PrimRep, a) -> (UpdFrameOffset, [FieldOffOrPadding a])
computeOffset UpdFrameOffset
bytes_so_far NonVoid (PrimRep, a)
nv_thing =
        (UpdFrameOffset
new_bytes_so_far, FieldOffOrPadding a -> [FieldOffOrPadding a]
forall a. FieldOffOrPadding a -> [FieldOffOrPadding a]
with_padding FieldOffOrPadding a
field_off)
      where
        (PrimRep
rep, a
thing) = NonVoid (PrimRep, a) -> (PrimRep, a)
forall a. NonVoid a -> a
fromNonVoid NonVoid (PrimRep, a)
nv_thing

        -- Size of the field in bytes.
        !sizeB :: UpdFrameOffset
sizeB = Platform -> PrimRep -> UpdFrameOffset
primRepSizeB Platform
platform PrimRep
rep

        -- Align the start offset (eg, 2-byte value should be 2-byte aligned).
        -- But not more than to a word.
        !align :: UpdFrameOffset
align = UpdFrameOffset -> UpdFrameOffset -> UpdFrameOffset
forall a. Ord a => a -> a -> a
min UpdFrameOffset
word_size UpdFrameOffset
sizeB
        !start :: UpdFrameOffset
start = UpdFrameOffset -> UpdFrameOffset -> UpdFrameOffset
roundUpTo UpdFrameOffset
bytes_so_far UpdFrameOffset
align
        !padding :: UpdFrameOffset
padding = UpdFrameOffset
start UpdFrameOffset -> UpdFrameOffset -> UpdFrameOffset
forall a. Num a => a -> a -> a
- UpdFrameOffset
bytes_so_far

        -- Final offset is:
        --   size of header + bytes_so_far + padding
        !final_offset :: UpdFrameOffset
final_offset = UpdFrameOffset
hdr_bytes UpdFrameOffset -> UpdFrameOffset -> UpdFrameOffset
forall a. Num a => a -> a -> a
+ UpdFrameOffset
bytes_so_far UpdFrameOffset -> UpdFrameOffset -> UpdFrameOffset
forall a. Num a => a -> a -> a
+ UpdFrameOffset
padding
        !new_bytes_so_far :: UpdFrameOffset
new_bytes_so_far = UpdFrameOffset
start UpdFrameOffset -> UpdFrameOffset -> UpdFrameOffset
forall a. Num a => a -> a -> a
+ UpdFrameOffset
sizeB
        field_off :: FieldOffOrPadding a
field_off = NonVoid a -> UpdFrameOffset -> FieldOffOrPadding a
forall a. NonVoid a -> UpdFrameOffset -> FieldOffOrPadding a
FieldOff (a -> NonVoid a
forall a. a -> NonVoid a
NonVoid a
thing) UpdFrameOffset
final_offset

        with_padding :: FieldOffOrPadding a -> [FieldOffOrPadding a]
with_padding FieldOffOrPadding a
field_off
            | UpdFrameOffset
padding UpdFrameOffset -> UpdFrameOffset -> Bool
forall a. Eq a => a -> a -> Bool
== UpdFrameOffset
0 = [FieldOffOrPadding a
field_off]
            | Bool
otherwise    = [ UpdFrameOffset -> UpdFrameOffset -> FieldOffOrPadding a
forall a. UpdFrameOffset -> UpdFrameOffset -> FieldOffOrPadding a
Padding UpdFrameOffset
padding (UpdFrameOffset
hdr_bytes UpdFrameOffset -> UpdFrameOffset -> UpdFrameOffset
forall a. Num a => a -> a -> a
+ UpdFrameOffset
bytes_so_far)
                             , FieldOffOrPadding a
field_off
                             ]


mkVirtHeapOffsets
  :: DynFlags
  -> ClosureHeader            -- What kind of header to account for
  -> [NonVoid (PrimRep,a)]    -- Things to make offsets for
  -> (WordOff,                -- _Total_ number of words allocated
      WordOff,                -- Number of words allocated for *pointers*
      [(NonVoid a, ByteOff)])
mkVirtHeapOffsets :: DynFlags
-> ClosureHeader
-> [NonVoid (PrimRep, a)]
-> (UpdFrameOffset, UpdFrameOffset, [(NonVoid a, UpdFrameOffset)])
mkVirtHeapOffsets DynFlags
dflags ClosureHeader
header [NonVoid (PrimRep, a)]
things =
    ( UpdFrameOffset
tot_wds
    , UpdFrameOffset
ptr_wds
    , [ (NonVoid a
field, UpdFrameOffset
offset) | (FieldOff NonVoid a
field UpdFrameOffset
offset) <- [FieldOffOrPadding a]
things_offsets ]
    )
  where
   (UpdFrameOffset
tot_wds, UpdFrameOffset
ptr_wds, [FieldOffOrPadding a]
things_offsets) =
       DynFlags
-> ClosureHeader
-> [NonVoid (PrimRep, a)]
-> (UpdFrameOffset, UpdFrameOffset, [FieldOffOrPadding a])
forall a.
DynFlags
-> ClosureHeader
-> [NonVoid (PrimRep, a)]
-> (UpdFrameOffset, UpdFrameOffset, [FieldOffOrPadding a])
mkVirtHeapOffsetsWithPadding DynFlags
dflags ClosureHeader
header [NonVoid (PrimRep, a)]
things

-- | Just like mkVirtHeapOffsets, but for constructors
mkVirtConstrOffsets
  :: DynFlags -> [NonVoid (PrimRep, a)]
  -> (WordOff, WordOff, [(NonVoid a, ByteOff)])
mkVirtConstrOffsets :: DynFlags
-> [NonVoid (PrimRep, a)]
-> (UpdFrameOffset, UpdFrameOffset, [(NonVoid a, UpdFrameOffset)])
mkVirtConstrOffsets DynFlags
dflags = DynFlags
-> ClosureHeader
-> [NonVoid (PrimRep, a)]
-> (UpdFrameOffset, UpdFrameOffset, [(NonVoid a, UpdFrameOffset)])
forall a.
DynFlags
-> ClosureHeader
-> [NonVoid (PrimRep, a)]
-> (UpdFrameOffset, UpdFrameOffset, [(NonVoid a, UpdFrameOffset)])
mkVirtHeapOffsets DynFlags
dflags ClosureHeader
StdHeader

-- | Just like mkVirtConstrOffsets, but used when we don't have the actual
-- arguments. Useful when e.g. generating info tables; we just need to know
-- sizes of pointer and non-pointer fields.
mkVirtConstrSizes :: DynFlags -> [NonVoid PrimRep] -> (WordOff, WordOff)
mkVirtConstrSizes :: DynFlags -> [NonVoid PrimRep] -> (UpdFrameOffset, UpdFrameOffset)
mkVirtConstrSizes DynFlags
dflags [NonVoid PrimRep]
field_reps
  = (UpdFrameOffset
tot_wds, UpdFrameOffset
ptr_wds)
  where
    (UpdFrameOffset
tot_wds, UpdFrameOffset
ptr_wds, [(NonVoid (), UpdFrameOffset)]
_) =
       DynFlags
-> [NonVoid (PrimRep, ())]
-> (UpdFrameOffset, UpdFrameOffset, [(NonVoid (), UpdFrameOffset)])
forall a.
DynFlags
-> [NonVoid (PrimRep, a)]
-> (UpdFrameOffset, UpdFrameOffset, [(NonVoid a, UpdFrameOffset)])
mkVirtConstrOffsets DynFlags
dflags
         ((NonVoid PrimRep -> NonVoid (PrimRep, ()))
-> [NonVoid PrimRep] -> [NonVoid (PrimRep, ())]
forall a b. (a -> b) -> [a] -> [b]
map (\NonVoid PrimRep
nv_rep -> (PrimRep, ()) -> NonVoid (PrimRep, ())
forall a. a -> NonVoid a
NonVoid (NonVoid PrimRep -> PrimRep
forall a. NonVoid a -> a
fromNonVoid NonVoid PrimRep
nv_rep, ())) [NonVoid PrimRep]
field_reps)

-------------------------------------------------------------------------
--
--        Making argument descriptors
--
--  An argument descriptor describes the layout of args on the stack,
--  both for         * GC (stack-layout) purposes, and
--                * saving/restoring registers when a heap-check fails
--
-- Void arguments aren't important, therefore (contrast constructSlowCall)
--
-------------------------------------------------------------------------

-- bring in ARG_P, ARG_N, etc.
#include "rts/storage/FunTypes.h"

mkArgDescr :: Platform -> [Id] -> ArgDescr
mkArgDescr :: Platform -> [Id] -> ArgDescr
mkArgDescr Platform
platform [Id]
args
  = let arg_bits :: [Bool]
arg_bits = Platform -> [ArgRep] -> [Bool]
argBits Platform
platform [ArgRep]
arg_reps
        arg_reps :: [ArgRep]
arg_reps = (ArgRep -> Bool) -> [ArgRep] -> [ArgRep]
forall a. (a -> Bool) -> [a] -> [a]
filter ArgRep -> Bool
isNonV ((Id -> ArgRep) -> [Id] -> [ArgRep]
forall a b. (a -> b) -> [a] -> [b]
map Id -> ArgRep
idArgRep [Id]
args)
           -- Getting rid of voids eases matching of standard patterns
    in case [ArgRep] -> Maybe UpdFrameOffset
stdPattern [ArgRep]
arg_reps of
         Just UpdFrameOffset
spec_id -> UpdFrameOffset -> ArgDescr
ArgSpec UpdFrameOffset
spec_id
         Maybe UpdFrameOffset
Nothing      -> [Bool] -> ArgDescr
ArgGen  [Bool]
arg_bits

argBits :: Platform -> [ArgRep] -> [Bool]        -- True for non-ptr, False for ptr
argBits :: Platform -> [ArgRep] -> [Bool]
argBits Platform
_         []           = []
argBits Platform
platform (ArgRep
P   : [ArgRep]
args) = Bool
False Bool -> [Bool] -> [Bool]
forall a. a -> [a] -> [a]
: Platform -> [ArgRep] -> [Bool]
argBits Platform
platform [ArgRep]
args
argBits Platform
platform (ArgRep
arg : [ArgRep]
args) = UpdFrameOffset -> [Bool] -> [Bool]
forall a. UpdFrameOffset -> [a] -> [a]
take (Platform -> ArgRep -> UpdFrameOffset
argRepSizeW Platform
platform ArgRep
arg) (Bool -> [Bool]
forall a. a -> [a]
repeat Bool
True)
                                 [Bool] -> [Bool] -> [Bool]
forall a. [a] -> [a] -> [a]
++ Platform -> [ArgRep] -> [Bool]
argBits Platform
platform [ArgRep]
args

----------------------
stdPattern :: [ArgRep] -> Maybe Int
stdPattern :: [ArgRep] -> Maybe UpdFrameOffset
stdPattern [ArgRep]
reps
  = case [ArgRep]
reps of
        []    -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_NONE        -- just void args, probably
        [ArgRep
N]   -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_N
        [ArgRep
P]   -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_P
        [ArgRep
F]   -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_F
        [ArgRep
D]   -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_D
        [ArgRep
L]   -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_L
        [ArgRep
V16] -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_V16
        [ArgRep
V32] -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_V32
        [ArgRep
V64] -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_V64

        [ArgRep
N,ArgRep
N] -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_NN
        [ArgRep
N,ArgRep
P] -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_NP
        [ArgRep
P,ArgRep
N] -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_PN
        [ArgRep
P,ArgRep
P] -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_PP

        [ArgRep
N,ArgRep
N,ArgRep
N] -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_NNN
        [ArgRep
N,ArgRep
N,ArgRep
P] -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_NNP
        [ArgRep
N,ArgRep
P,ArgRep
N] -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_NPN
        [ArgRep
N,ArgRep
P,ArgRep
P] -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_NPP
        [ArgRep
P,ArgRep
N,ArgRep
N] -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_PNN
        [ArgRep
P,ArgRep
N,ArgRep
P] -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_PNP
        [ArgRep
P,ArgRep
P,ArgRep
N] -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_PPN
        [ArgRep
P,ArgRep
P,ArgRep
P] -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_PPP

        [ArgRep
P,ArgRep
P,ArgRep
P,ArgRep
P]     -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_PPPP
        [ArgRep
P,ArgRep
P,ArgRep
P,ArgRep
P,ArgRep
P]   -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_PPPPP
        [ArgRep
P,ArgRep
P,ArgRep
P,ArgRep
P,ArgRep
P,ArgRep
P] -> UpdFrameOffset -> Maybe UpdFrameOffset
forall a. a -> Maybe a
Just ARG_PPPPPP

        [ArgRep]
_ -> Maybe UpdFrameOffset
forall a. Maybe a
Nothing

-------------------------------------------------------------------------
--
--        Generating the info table and code for a closure
--
-------------------------------------------------------------------------

-- Here we make an info table of type 'CmmInfo'.  The concrete
-- representation as a list of 'CmmAddr' is handled later
-- in the pipeline by 'cmmToRawCmm'.
-- When loading the free variables, a function closure pointer may be tagged,
-- so we must take it into account.

emitClosureProcAndInfoTable :: Bool                    -- top-level?
                            -> Id                      -- name of the closure
                            -> LambdaFormInfo
                            -> CmmInfoTable
                            -> [NonVoid Id]            -- incoming arguments
                            -> ((Int, LocalReg, [LocalReg]) -> FCode ()) -- function body
                            -> FCode ()
emitClosureProcAndInfoTable :: Bool
-> Id
-> LambdaFormInfo
-> CmmInfoTable
-> [NonVoid Id]
-> ((UpdFrameOffset, LocalReg, [LocalReg]) -> FCode ())
-> FCode ()
emitClosureProcAndInfoTable Bool
top_lvl Id
bndr LambdaFormInfo
lf_info CmmInfoTable
info_tbl [NonVoid Id]
args (UpdFrameOffset, LocalReg, [LocalReg]) -> FCode ()
body
 = do   { DynFlags
dflags <- FCode DynFlags
forall (m :: * -> *). HasDynFlags m => m DynFlags
getDynFlags
        ; Platform
platform <- FCode Platform
getPlatform
        -- Bind the binder itself, but only if it's not a top-level
        -- binding. We need non-top let-bindings to refer to the
        -- top-level binding, which this binding would incorrectly shadow.
        ; LocalReg
node <- if Bool
top_lvl then LocalReg -> FCode LocalReg
forall (m :: * -> *) a. Monad m => a -> m a
return (LocalReg -> FCode LocalReg) -> LocalReg -> FCode LocalReg
forall a b. (a -> b) -> a -> b
$ Platform -> NonVoid Id -> LocalReg
idToReg Platform
platform (Id -> NonVoid Id
forall a. a -> NonVoid a
NonVoid Id
bndr)
                  else NonVoid Id -> LambdaFormInfo -> FCode LocalReg
bindToReg (Id -> NonVoid Id
forall a. a -> NonVoid a
NonVoid Id
bndr) LambdaFormInfo
lf_info
        ; let node_points :: Bool
node_points = DynFlags -> LambdaFormInfo -> Bool
nodeMustPointToIt DynFlags
dflags LambdaFormInfo
lf_info
        ; [LocalReg]
arg_regs <- [NonVoid Id] -> FCode [LocalReg]
bindArgsToRegs [NonVoid Id]
args
        ; let args' :: [LocalReg]
args' = if Bool
node_points then (LocalReg
node LocalReg -> [LocalReg] -> [LocalReg]
forall a. a -> [a] -> [a]
: [LocalReg]
arg_regs) else [LocalReg]
arg_regs
              conv :: Convention
conv  = if DynFlags -> LambdaFormInfo -> Bool
nodeMustPointToIt DynFlags
dflags LambdaFormInfo
lf_info then Convention
NativeNodeCall
                                                          else Convention
NativeDirectCall
              (UpdFrameOffset
offset, [GlobalReg]
_, CmmAGraph
_) = DynFlags
-> Convention
-> [LocalReg]
-> [LocalReg]
-> (UpdFrameOffset, [GlobalReg], CmmAGraph)
mkCallEntry DynFlags
dflags Convention
conv [LocalReg]
args' []
        ; CmmInfoTable -> Convention -> [LocalReg] -> FCode () -> FCode ()
emitClosureAndInfoTable CmmInfoTable
info_tbl Convention
conv [LocalReg]
args' (FCode () -> FCode ()) -> FCode () -> FCode ()
forall a b. (a -> b) -> a -> b
$ (UpdFrameOffset, LocalReg, [LocalReg]) -> FCode ()
body (UpdFrameOffset
offset, LocalReg
node, [LocalReg]
arg_regs)
        }

-- Data constructors need closures, but not with all the argument handling
-- needed for functions. The shared part goes here.
emitClosureAndInfoTable ::
  CmmInfoTable -> Convention -> [LocalReg] -> FCode () -> FCode ()
emitClosureAndInfoTable :: CmmInfoTable -> Convention -> [LocalReg] -> FCode () -> FCode ()
emitClosureAndInfoTable CmmInfoTable
info_tbl Convention
conv [LocalReg]
args FCode ()
body
  = do { (()
_, CmmAGraphScoped
blks) <- FCode () -> FCode ((), CmmAGraphScoped)
forall a. FCode a -> FCode (a, CmmAGraphScoped)
getCodeScoped FCode ()
body
       ; let entry_lbl :: CLabel
entry_lbl = CLabel -> CLabel
toEntryLbl (CmmInfoTable -> CLabel
cit_lbl CmmInfoTable
info_tbl)
       ; Convention
-> Maybe CmmInfoTable
-> CLabel
-> [LocalReg]
-> CmmAGraphScoped
-> FCode ()
emitProcWithConvention Convention
conv (CmmInfoTable -> Maybe CmmInfoTable
forall a. a -> Maybe a
Just CmmInfoTable
info_tbl) CLabel
entry_lbl [LocalReg]
args CmmAGraphScoped
blks
       }