module GHC.Cmm.CallConv (
  ParamLocation(..),
  assignArgumentsPos,
  assignStack,
  realArgRegsCover,
  allArgRegsCover
) where

import GHC.Prelude
import Data.List (nub)

import GHC.Cmm.Expr
import GHC.Runtime.Heap.Layout
import GHC.Cmm (Convention(..))

import GHC.Platform
import GHC.Platform.Profile
import GHC.Utils.Outputable
import GHC.Utils.Panic

-- Calculate the 'GlobalReg' or stack locations for function call
-- parameters as used by the Cmm calling convention.

data ParamLocation
  = RegisterParam GlobalReg
  | StackParam ByteOff

instance Outputable ParamLocation where
  ppr :: ParamLocation -> SDoc
ppr (RegisterParam GlobalReg
g) = GlobalReg -> SDoc
forall a. Outputable a => a -> SDoc
ppr GlobalReg
g
  ppr (StackParam Int
p)    = Int -> SDoc
forall a. Outputable a => a -> SDoc
ppr Int
p

-- |
-- Given a list of arguments, and a function that tells their types,
-- return a list showing where each argument is passed
--
assignArgumentsPos :: Profile
                   -> ByteOff           -- stack offset to start with
                   -> Convention
                   -> (a -> CmmType)    -- how to get a type from an arg
                   -> [a]               -- args
                   -> (
                        ByteOff              -- bytes of stack args
                      , [(a, ParamLocation)] -- args and locations
                      )

assignArgumentsPos :: forall a.
Profile
-> Int
-> Convention
-> (a -> CmmType)
-> [a]
-> (Int, [(a, ParamLocation)])
assignArgumentsPos Profile
profile Int
off Convention
conv a -> CmmType
arg_ty [a]
reps = (Int
stk_off, [(a, ParamLocation)]
assignments)
    where
      platform :: Platform
platform = Profile -> Platform
profilePlatform Profile
profile
      regs :: AvailRegs
regs = case ([a]
reps, Convention
conv) of
               ([a]
_,   Convention
NativeNodeCall)   -> Platform -> AvailRegs
getRegsWithNode Platform
platform
               ([a]
_,   Convention
NativeDirectCall) -> Platform -> AvailRegs
getRegsWithoutNode Platform
platform
               ([a
_], Convention
NativeReturn)     -> Platform -> AvailRegs
allRegs Platform
platform
               ([a]
_,   Convention
NativeReturn)     -> Platform -> AvailRegs
getRegsWithNode Platform
platform
               -- GC calling convention *must* put values in registers
               ([a]
_,   Convention
GC)               -> Platform -> AvailRegs
allRegs Platform
platform
               ([a]
_,   Convention
Slow)             -> AvailRegs
nodeOnly
      -- The calling conventions first assign arguments to registers,
      -- then switch to the stack when we first run out of registers
      -- (even if there are still available registers for args of a
      -- different type).  When returning an unboxed tuple, we also
      -- separate the stack arguments by pointerhood.
      ([(a, ParamLocation)]
reg_assts, [a]
stk_args)  = [(a, ParamLocation)]
-> [a] -> AvailRegs -> ([(a, ParamLocation)], [a])
assign_regs [] [a]
reps AvailRegs
regs
      (Int
stk_off,   [(a, ParamLocation)]
stk_assts) = Platform
-> Int -> (a -> CmmType) -> [a] -> (Int, [(a, ParamLocation)])
forall a.
Platform
-> Int -> (a -> CmmType) -> [a] -> (Int, [(a, ParamLocation)])
assignStack Platform
platform Int
off a -> CmmType
arg_ty [a]
stk_args
      assignments :: [(a, ParamLocation)]
assignments = [(a, ParamLocation)]
reg_assts [(a, ParamLocation)]
-> [(a, ParamLocation)] -> [(a, ParamLocation)]
forall a. [a] -> [a] -> [a]
++ [(a, ParamLocation)]
stk_assts

      assign_regs :: [(a, ParamLocation)]
-> [a] -> AvailRegs -> ([(a, ParamLocation)], [a])
assign_regs [(a, ParamLocation)]
assts []     AvailRegs
_    = ([(a, ParamLocation)]
assts, [])
      assign_regs [(a, ParamLocation)]
assts (a
r:[a]
rs) AvailRegs
regs | CmmType -> Bool
isVecType CmmType
ty   = ([(a, ParamLocation)], [a])
vec
                                    | CmmType -> Bool
isFloatType CmmType
ty = ([(a, ParamLocation)], [a])
float
                                    | Bool
otherwise      = ([(a, ParamLocation)], [a])
int
        where vec :: ([(a, ParamLocation)], [a])
vec = case (Width
w, AvailRegs
regs) of
                      (Width
W128, AvailRegs [GlobalReg]
vs [GlobalReg]
fs [GlobalReg]
ds [GlobalReg]
ls (Int
s:[Int]
ss))
                          | Width -> Profile -> Bool
passVectorInReg Width
W128 Profile
profile -> (ParamLocation, AvailRegs) -> ([(a, ParamLocation)], [a])
k (GlobalReg -> ParamLocation
RegisterParam (Int -> GlobalReg
XmmReg Int
s), [GlobalReg]
-> [GlobalReg] -> [GlobalReg] -> [GlobalReg] -> [Int] -> AvailRegs
AvailRegs [GlobalReg]
vs [GlobalReg]
fs [GlobalReg]
ds [GlobalReg]
ls [Int]
ss)
                      (Width
W256, AvailRegs [GlobalReg]
vs [GlobalReg]
fs [GlobalReg]
ds [GlobalReg]
ls (Int
s:[Int]
ss))
                          | Width -> Profile -> Bool
passVectorInReg Width
W256 Profile
profile -> (ParamLocation, AvailRegs) -> ([(a, ParamLocation)], [a])
k (GlobalReg -> ParamLocation
RegisterParam (Int -> GlobalReg
YmmReg Int
s), [GlobalReg]
-> [GlobalReg] -> [GlobalReg] -> [GlobalReg] -> [Int] -> AvailRegs
AvailRegs [GlobalReg]
vs [GlobalReg]
fs [GlobalReg]
ds [GlobalReg]
ls [Int]
ss)
                      (Width
W512, AvailRegs [GlobalReg]
vs [GlobalReg]
fs [GlobalReg]
ds [GlobalReg]
ls (Int
s:[Int]
ss))
                          | Width -> Profile -> Bool
passVectorInReg Width
W512 Profile
profile -> (ParamLocation, AvailRegs) -> ([(a, ParamLocation)], [a])
k (GlobalReg -> ParamLocation
RegisterParam (Int -> GlobalReg
ZmmReg Int
s), [GlobalReg]
-> [GlobalReg] -> [GlobalReg] -> [GlobalReg] -> [Int] -> AvailRegs
AvailRegs [GlobalReg]
vs [GlobalReg]
fs [GlobalReg]
ds [GlobalReg]
ls [Int]
ss)
                      (Width, AvailRegs)
_ -> ([(a, ParamLocation)]
assts, (a
ra -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
rs))
              float :: ([(a, ParamLocation)], [a])
float = case (Width
w, AvailRegs
regs) of
                        (Width
W32, AvailRegs [GlobalReg]
vs [GlobalReg]
fs [GlobalReg]
ds [GlobalReg]
ls (Int
s:[Int]
ss))
                            | Bool
passFloatInXmm          -> (ParamLocation, AvailRegs) -> ([(a, ParamLocation)], [a])
k (GlobalReg -> ParamLocation
RegisterParam (Int -> GlobalReg
FloatReg Int
s), [GlobalReg]
-> [GlobalReg] -> [GlobalReg] -> [GlobalReg] -> [Int] -> AvailRegs
AvailRegs [GlobalReg]
vs [GlobalReg]
fs [GlobalReg]
ds [GlobalReg]
ls [Int]
ss)
                        (Width
W32, AvailRegs [GlobalReg]
vs (GlobalReg
f:[GlobalReg]
fs) [GlobalReg]
ds [GlobalReg]
ls [Int]
ss)
                            | Bool -> Bool
not Bool
passFloatInXmm      -> (ParamLocation, AvailRegs) -> ([(a, ParamLocation)], [a])
k (GlobalReg -> ParamLocation
RegisterParam GlobalReg
f, [GlobalReg]
-> [GlobalReg] -> [GlobalReg] -> [GlobalReg] -> [Int] -> AvailRegs
AvailRegs [GlobalReg]
vs [GlobalReg]
fs [GlobalReg]
ds [GlobalReg]
ls [Int]
ss)
                        (Width
W64, AvailRegs [GlobalReg]
vs [GlobalReg]
fs [GlobalReg]
ds [GlobalReg]
ls (Int
s:[Int]
ss))
                            | Bool
passFloatInXmm          -> (ParamLocation, AvailRegs) -> ([(a, ParamLocation)], [a])
k (GlobalReg -> ParamLocation
RegisterParam (Int -> GlobalReg
DoubleReg Int
s), [GlobalReg]
-> [GlobalReg] -> [GlobalReg] -> [GlobalReg] -> [Int] -> AvailRegs
AvailRegs [GlobalReg]
vs [GlobalReg]
fs [GlobalReg]
ds [GlobalReg]
ls [Int]
ss)
                        (Width
W64, AvailRegs [GlobalReg]
vs [GlobalReg]
fs (GlobalReg
d:[GlobalReg]
ds) [GlobalReg]
ls [Int]
ss)
                            | Bool -> Bool
not Bool
passFloatInXmm      -> (ParamLocation, AvailRegs) -> ([(a, ParamLocation)], [a])
k (GlobalReg -> ParamLocation
RegisterParam GlobalReg
d, [GlobalReg]
-> [GlobalReg] -> [GlobalReg] -> [GlobalReg] -> [Int] -> AvailRegs
AvailRegs [GlobalReg]
vs [GlobalReg]
fs [GlobalReg]
ds [GlobalReg]
ls [Int]
ss)
                        (Width, AvailRegs)
_ -> ([(a, ParamLocation)]
assts, (a
ra -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
rs))
              int :: ([(a, ParamLocation)], [a])
int = case (Width
w, AvailRegs
regs) of
                      (Width
W128, AvailRegs
_) -> String -> ([(a, ParamLocation)], [a])
forall a. HasCallStack => String -> a
panic String
"W128 unsupported register type"
                      (Width
_, AvailRegs (GlobalReg
v:[GlobalReg]
vs) [GlobalReg]
fs [GlobalReg]
ds [GlobalReg]
ls [Int]
ss) | Width -> Int
widthInBits Width
w Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Width -> Int
widthInBits (Platform -> Width
wordWidth Platform
platform)
                          -> (ParamLocation, AvailRegs) -> ([(a, ParamLocation)], [a])
k (GlobalReg -> ParamLocation
RegisterParam GlobalReg
v, [GlobalReg]
-> [GlobalReg] -> [GlobalReg] -> [GlobalReg] -> [Int] -> AvailRegs
AvailRegs [GlobalReg]
vs [GlobalReg]
fs [GlobalReg]
ds [GlobalReg]
ls [Int]
ss)
                      (Width
_, AvailRegs [GlobalReg]
vs [GlobalReg]
fs [GlobalReg]
ds (GlobalReg
l:[GlobalReg]
ls) [Int]
ss) | Width -> Int
widthInBits Width
w Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Width -> Int
widthInBits (Platform -> Width
wordWidth Platform
platform)
                          -> (ParamLocation, AvailRegs) -> ([(a, ParamLocation)], [a])
k (GlobalReg -> ParamLocation
RegisterParam GlobalReg
l, [GlobalReg]
-> [GlobalReg] -> [GlobalReg] -> [GlobalReg] -> [Int] -> AvailRegs
AvailRegs [GlobalReg]
vs [GlobalReg]
fs [GlobalReg]
ds [GlobalReg]
ls [Int]
ss)
                      (Width, AvailRegs)
_   -> ([(a, ParamLocation)]
assts, (a
ra -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
rs))
              k :: (ParamLocation, AvailRegs) -> ([(a, ParamLocation)], [a])
k (ParamLocation
asst, AvailRegs
regs') = [(a, ParamLocation)]
-> [a] -> AvailRegs -> ([(a, ParamLocation)], [a])
assign_regs ((a
r, ParamLocation
asst) (a, ParamLocation) -> [(a, ParamLocation)] -> [(a, ParamLocation)]
forall a. a -> [a] -> [a]
: [(a, ParamLocation)]
assts) [a]
rs AvailRegs
regs'
              ty :: CmmType
ty = a -> CmmType
arg_ty a
r
              w :: Width
w  = CmmType -> Width
typeWidth CmmType
ty
              passFloatInXmm :: Bool
passFloatInXmm = Platform -> Bool
passFloatArgsInXmm Platform
platform

passFloatArgsInXmm :: Platform -> Bool
passFloatArgsInXmm :: Platform -> Bool
passFloatArgsInXmm Platform
platform = case Platform -> Arch
platformArch Platform
platform of
                              Arch
ArchX86_64 -> Bool
True
                              Arch
ArchX86    -> Bool
False
                              Arch
_          -> Bool
False

-- We used to spill vector registers to the stack since the LLVM backend didn't
-- support vector registers in its calling convention. However, this has now
-- been fixed. This function remains only as a convenient way to re-enable
-- spilling when debugging code generation.
passVectorInReg :: Width -> Profile -> Bool
passVectorInReg :: Width -> Profile -> Bool
passVectorInReg Width
_ Profile
_ = Bool
True

assignStack :: Platform -> ByteOff -> (a -> CmmType) -> [a]
            -> (
                 ByteOff              -- bytes of stack args
               , [(a, ParamLocation)] -- args and locations
               )
assignStack :: forall a.
Platform
-> Int -> (a -> CmmType) -> [a] -> (Int, [(a, ParamLocation)])
assignStack Platform
platform Int
offset a -> CmmType
arg_ty [a]
args = Int -> [(a, ParamLocation)] -> [a] -> (Int, [(a, ParamLocation)])
assign_stk Int
offset [] ([a] -> [a]
forall a. [a] -> [a]
reverse [a]
args)
 where
      assign_stk :: Int -> [(a, ParamLocation)] -> [a] -> (Int, [(a, ParamLocation)])
assign_stk Int
offset [(a, ParamLocation)]
assts [] = (Int
offset, [(a, ParamLocation)]
assts)
      assign_stk Int
offset [(a, ParamLocation)]
assts (a
r:[a]
rs)
        = Int -> [(a, ParamLocation)] -> [a] -> (Int, [(a, ParamLocation)])
assign_stk Int
off' ((a
r, Int -> ParamLocation
StackParam Int
off') (a, ParamLocation) -> [(a, ParamLocation)] -> [(a, ParamLocation)]
forall a. a -> [a] -> [a]
: [(a, ParamLocation)]
assts) [a]
rs
        where w :: Width
w    = CmmType -> Width
typeWidth (a -> CmmType
arg_ty a
r)
              off' :: Int
off' = Int
offset Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
size
              -- Stack arguments always take a whole number of words, we never
              -- pack them unlike constructor fields.
              size :: Int
size = Platform -> Int -> Int
roundUpToWords Platform
platform (Width -> Int
widthInBytes Width
w)

-----------------------------------------------------------------------------
-- Local information about the registers available

-- | Keep track of locally available registers.
data AvailRegs
  = AvailRegs
    { AvailRegs -> [GlobalReg]
availVanillaRegs :: [GlobalReg]
       -- ^ Available vanilla registers
    , AvailRegs -> [GlobalReg]
availFloatRegs   :: [GlobalReg]
       -- ^ Available float registers
    , AvailRegs -> [GlobalReg]
availDoubleRegs  :: [GlobalReg]
       -- ^ Available double registers
    , AvailRegs -> [GlobalReg]
availLongRegs    :: [GlobalReg]
       -- ^ Available long registers
    , AvailRegs -> [Int]
availXMMRegs     :: [Int]
       -- ^ Available vector XMM registers
    }

noAvailRegs :: AvailRegs
noAvailRegs :: AvailRegs
noAvailRegs = [GlobalReg]
-> [GlobalReg] -> [GlobalReg] -> [GlobalReg] -> [Int] -> AvailRegs
AvailRegs [] [] [] [] []

-- Vanilla registers can contain pointers, Ints, Chars.
-- Floats and doubles have separate register supplies.
--
-- We take these register supplies from the *real* registers, i.e. those
-- that are guaranteed to map to machine registers.

getRegsWithoutNode, getRegsWithNode :: Platform -> AvailRegs
getRegsWithoutNode :: Platform -> AvailRegs
getRegsWithoutNode Platform
platform =
  AvailRegs
   { availVanillaRegs :: [GlobalReg]
availVanillaRegs = (GlobalReg -> Bool) -> [GlobalReg] -> [GlobalReg]
forall a. (a -> Bool) -> [a] -> [a]
filter (\GlobalReg
r -> GlobalReg
r GlobalReg -> GlobalReg -> Bool
forall a. Eq a => a -> a -> Bool
/= GlobalReg
node) (Platform -> [GlobalReg]
realVanillaRegs Platform
platform)
   , availFloatRegs :: [GlobalReg]
availFloatRegs   = Platform -> [GlobalReg]
realFloatRegs Platform
platform
   , availDoubleRegs :: [GlobalReg]
availDoubleRegs  = Platform -> [GlobalReg]
realDoubleRegs Platform
platform
   , availLongRegs :: [GlobalReg]
availLongRegs    = Platform -> [GlobalReg]
realLongRegs Platform
platform
   , availXMMRegs :: [Int]
availXMMRegs     = Platform -> [Int]
realXmmRegNos Platform
platform }

-- getRegsWithNode uses R1/node even if it isn't a register
getRegsWithNode :: Platform -> AvailRegs
getRegsWithNode Platform
platform =
  AvailRegs
   { availVanillaRegs :: [GlobalReg]
availVanillaRegs = if [GlobalReg] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (Platform -> [GlobalReg]
realVanillaRegs Platform
platform)
                        then [Int -> GlobalReg
VanillaReg Int
1]
                        else Platform -> [GlobalReg]
realVanillaRegs Platform
platform
   , availFloatRegs :: [GlobalReg]
availFloatRegs   = Platform -> [GlobalReg]
realFloatRegs Platform
platform
   , availDoubleRegs :: [GlobalReg]
availDoubleRegs  = Platform -> [GlobalReg]
realDoubleRegs Platform
platform
   , availLongRegs :: [GlobalReg]
availLongRegs    = Platform -> [GlobalReg]
realLongRegs Platform
platform
   , availXMMRegs :: [Int]
availXMMRegs     = Platform -> [Int]
realXmmRegNos Platform
platform }

allFloatRegs, allDoubleRegs, allLongRegs :: Platform -> [GlobalReg]
allVanillaRegs :: Platform -> [GlobalReg]
allXmmRegs :: Platform -> [Int]

allVanillaRegs :: Platform -> [GlobalReg]
allVanillaRegs Platform
platform = (Int -> GlobalReg) -> [Int] -> [GlobalReg]
forall a b. (a -> b) -> [a] -> [b]
map Int -> GlobalReg
VanillaReg ([Int] -> [GlobalReg]) -> [Int] -> [GlobalReg]
forall a b. (a -> b) -> a -> b
$ Int -> [Int]
regList (PlatformConstants -> Int
pc_MAX_Vanilla_REG (Platform -> PlatformConstants
platformConstants Platform
platform))
allFloatRegs :: Platform -> [GlobalReg]
allFloatRegs   Platform
platform = (Int -> GlobalReg) -> [Int] -> [GlobalReg]
forall a b. (a -> b) -> [a] -> [b]
map Int -> GlobalReg
FloatReg   ([Int] -> [GlobalReg]) -> [Int] -> [GlobalReg]
forall a b. (a -> b) -> a -> b
$ Int -> [Int]
regList (PlatformConstants -> Int
pc_MAX_Float_REG   (Platform -> PlatformConstants
platformConstants Platform
platform))
allDoubleRegs :: Platform -> [GlobalReg]
allDoubleRegs  Platform
platform = (Int -> GlobalReg) -> [Int] -> [GlobalReg]
forall a b. (a -> b) -> [a] -> [b]
map Int -> GlobalReg
DoubleReg  ([Int] -> [GlobalReg]) -> [Int] -> [GlobalReg]
forall a b. (a -> b) -> a -> b
$ Int -> [Int]
regList (PlatformConstants -> Int
pc_MAX_Double_REG  (Platform -> PlatformConstants
platformConstants Platform
platform))
allLongRegs :: Platform -> [GlobalReg]
allLongRegs    Platform
platform = (Int -> GlobalReg) -> [Int] -> [GlobalReg]
forall a b. (a -> b) -> [a] -> [b]
map Int -> GlobalReg
LongReg    ([Int] -> [GlobalReg]) -> [Int] -> [GlobalReg]
forall a b. (a -> b) -> a -> b
$ Int -> [Int]
regList (PlatformConstants -> Int
pc_MAX_Long_REG    (Platform -> PlatformConstants
platformConstants Platform
platform))
allXmmRegs :: Platform -> [Int]
allXmmRegs     Platform
platform =                  Int -> [Int]
regList (PlatformConstants -> Int
pc_MAX_XMM_REG     (Platform -> PlatformConstants
platformConstants Platform
platform))

realFloatRegs, realDoubleRegs, realLongRegs :: Platform -> [GlobalReg]
realVanillaRegs :: Platform -> [GlobalReg]

realVanillaRegs :: Platform -> [GlobalReg]
realVanillaRegs Platform
platform = (Int -> GlobalReg) -> [Int] -> [GlobalReg]
forall a b. (a -> b) -> [a] -> [b]
map Int -> GlobalReg
VanillaReg ([Int] -> [GlobalReg]) -> [Int] -> [GlobalReg]
forall a b. (a -> b) -> a -> b
$ Int -> [Int]
regList (PlatformConstants -> Int
pc_MAX_Real_Vanilla_REG (Platform -> PlatformConstants
platformConstants Platform
platform))
realFloatRegs :: Platform -> [GlobalReg]
realFloatRegs   Platform
platform = (Int -> GlobalReg) -> [Int] -> [GlobalReg]
forall a b. (a -> b) -> [a] -> [b]
map Int -> GlobalReg
FloatReg   ([Int] -> [GlobalReg]) -> [Int] -> [GlobalReg]
forall a b. (a -> b) -> a -> b
$ Int -> [Int]
regList (PlatformConstants -> Int
pc_MAX_Real_Float_REG   (Platform -> PlatformConstants
platformConstants Platform
platform))
realDoubleRegs :: Platform -> [GlobalReg]
realDoubleRegs  Platform
platform = (Int -> GlobalReg) -> [Int] -> [GlobalReg]
forall a b. (a -> b) -> [a] -> [b]
map Int -> GlobalReg
DoubleReg  ([Int] -> [GlobalReg]) -> [Int] -> [GlobalReg]
forall a b. (a -> b) -> a -> b
$ Int -> [Int]
regList (PlatformConstants -> Int
pc_MAX_Real_Double_REG  (Platform -> PlatformConstants
platformConstants Platform
platform))
realLongRegs :: Platform -> [GlobalReg]
realLongRegs    Platform
platform = (Int -> GlobalReg) -> [Int] -> [GlobalReg]
forall a b. (a -> b) -> [a] -> [b]
map Int -> GlobalReg
LongReg    ([Int] -> [GlobalReg]) -> [Int] -> [GlobalReg]
forall a b. (a -> b) -> a -> b
$ Int -> [Int]
regList (PlatformConstants -> Int
pc_MAX_Real_Long_REG    (Platform -> PlatformConstants
platformConstants Platform
platform))

realXmmRegNos :: Platform -> [Int]
realXmmRegNos :: Platform -> [Int]
realXmmRegNos Platform
platform
    | Platform -> Bool
isSse2Enabled Platform
platform = Int -> [Int]
regList (PlatformConstants -> Int
pc_MAX_Real_XMM_REG (Platform -> PlatformConstants
platformConstants Platform
platform))
    | Bool
otherwise              = []

regList :: Int -> [Int]
regList :: Int -> [Int]
regList Int
n = [Int
1 .. Int
n]

allRegs :: Platform -> AvailRegs
allRegs :: Platform -> AvailRegs
allRegs Platform
platform =
  AvailRegs
   { availVanillaRegs :: [GlobalReg]
availVanillaRegs = Platform -> [GlobalReg]
allVanillaRegs Platform
platform
   , availFloatRegs :: [GlobalReg]
availFloatRegs   = Platform -> [GlobalReg]
allFloatRegs   Platform
platform
   , availDoubleRegs :: [GlobalReg]
availDoubleRegs  = Platform -> [GlobalReg]
allDoubleRegs  Platform
platform
   , availLongRegs :: [GlobalReg]
availLongRegs    = Platform -> [GlobalReg]
allLongRegs    Platform
platform
   , availXMMRegs :: [Int]
availXMMRegs     = Platform -> [Int]
allXmmRegs     Platform
platform }

nodeOnly :: AvailRegs
nodeOnly :: AvailRegs
nodeOnly = AvailRegs
noAvailRegs { availVanillaRegs = [VanillaReg 1] }

-- This returns the set of global registers that *cover* the machine registers
-- used for argument passing. On platforms where registers can overlap---right
-- now just x86-64, where Float and Double registers overlap---passing this set
-- of registers is guaranteed to preserve the contents of all live registers. We
-- only use this functionality in hand-written C-- code in the RTS.
realArgRegsCover :: Platform -> [GlobalReg]
realArgRegsCover :: Platform -> [GlobalReg]
realArgRegsCover Platform
platform
    | Platform -> Bool
passFloatArgsInXmm Platform
platform
    = Platform -> [GlobalReg]
realVanillaRegs    Platform
platform [GlobalReg] -> [GlobalReg] -> [GlobalReg]
forall a. [a] -> [a] -> [a]
++
      Platform -> [GlobalReg]
realLongRegs       Platform
platform [GlobalReg] -> [GlobalReg] -> [GlobalReg]
forall a. [a] -> [a] -> [a]
++
      Platform -> [GlobalReg]
realDoubleRegs     Platform
platform
        -- we only need to save the low Double part of XMM registers.
        -- Moreover, the NCG can't load/store full XMM
        -- registers for now...

    | Bool
otherwise
    = Platform -> [GlobalReg]
realVanillaRegs Platform
platform [GlobalReg] -> [GlobalReg] -> [GlobalReg]
forall a. [a] -> [a] -> [a]
++
      Platform -> [GlobalReg]
realFloatRegs   Platform
platform [GlobalReg] -> [GlobalReg] -> [GlobalReg]
forall a. [a] -> [a] -> [a]
++
      Platform -> [GlobalReg]
realDoubleRegs  Platform
platform [GlobalReg] -> [GlobalReg] -> [GlobalReg]
forall a. [a] -> [a] -> [a]
++
      Platform -> [GlobalReg]
realLongRegs    Platform
platform
        -- we don't save XMM registers if they are not used for parameter passing


{-

  Note [GHCi and native call registers]
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  The GHCi bytecode interpreter does not have access to the STG registers
  that the native calling convention uses for passing arguments. It uses
  helper stack frames to move values between the stack and registers.

  If only a single register needs to be moved, GHCi uses a specific stack
  frame. For example stg_ctoi_R1p saves a heap pointer value from STG register
  R1 and stg_ctoi_D1 saves a double precision floating point value from D1.
  In the other direction, helpers stg_ret_p and stg_ret_d move a value from
  the stack to the R1 and D1 registers, respectively.

  When GHCi needs to move more than one register it cannot use a specific
  helper frame. It would simply be impossible to create a helper for all
  possible combinations of register values. Instead, there are generic helper
  stack frames that use a call_info word that describes the active registers
  and the number of stack words used by the arguments of a call.

  These helper stack frames are currently:

      - stg_ret_t:    return a tuple to the continuation at the top of
                          the stack
      - stg_ctoi_t:   convert a tuple return value to be used in
                          bytecode
      - stg_primcall: call a function


  The call_info word contains a bitmap of the active registers
  for the call and and a stack offset. The layout is as follows:

      - bit 0-23:  Bitmap of active registers for the call, the
                   order corresponds to the list returned by
                   allArgRegsCover. For example if bit 0 (the least
                   significant bit) is set, the first register in the
                   allArgRegsCover list is active. Bit 1 for the
                   second register in the list and so on.

      - bit 24-31: Unsigned byte indicating the stack offset
                   of the continuation in words. For tuple returns
                   this is the number of words returned on the
                   stack. For primcalls this field is unused, since
                   we don't jump to a continuation.

    The upper 32 bits on 64 bit platforms are currently unused.

    If a register is smaller than a word on the stack (for example a
    single precision float on a 64 bit system), then the stack slot
    is padded to a whole word.

    Example:

        If a tuple is returned in three registers and an additional two
        words on the stack, then three bits in the register bitmap
        (bits 0-23) would be set. And bit 24-31 would be
        00000010 (two in binary).

        The values on the stack before a call to POP_ARG_REGS would
        be as follows:

            ...
            continuation
            stack_arg_1
            stack_arg_2
            register_arg_3
            register_arg_2
            register_arg_1 <- Sp

        A call to POP_ARG_REGS(call_info) would move register_arg_1
        to the register corresponding to the lowest set bit in the
        call_info word. register_arg_2 would be moved to the register
        corresponding to the second lowest set bit, and so on.

        After POP_ARG_REGS(call_info), the stack pointer Sp points
        to the topmost stack argument, so the stack looks as follows:

            ...
            continuation
            stack_arg_1
            stack_arg_2 <- Sp

        At this point all the arguments are in place and we are ready
        to jump to the continuation, the location (offset from Sp) of
        which is found by inspecting the value of bits 24-31. In this
        case the offset is two words.

    On x86_64, the double precision (Dn) and single precision
    floating (Fn) point registers overlap, e.g. D1 uses the same
    physical register as F1. On this platform, the list returned
    by allArgRegsCover contains only entries for the double
    precision registers. If an argument is passed in register
    Fn, the bit corresponding to Dn should be set.

  Note: if anything changes in how registers for native calls overlap,
           make sure to also update GHC.StgToByteCode.layoutNativeCall
 -}

-- Like realArgRegsCover but always includes the node. This covers all real
-- and virtual registers actually used for passing arguments.

allArgRegsCover :: Platform -> [GlobalReg]
allArgRegsCover :: Platform -> [GlobalReg]
allArgRegsCover Platform
platform =
  [GlobalReg] -> [GlobalReg]
forall a. Eq a => [a] -> [a]
nub (Int -> GlobalReg
VanillaReg Int
1 GlobalReg -> [GlobalReg] -> [GlobalReg]
forall a. a -> [a] -> [a]
: Platform -> [GlobalReg]
realArgRegsCover Platform
platform)