    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE LambdaCase #-}
    {-# LANGUAGE MultiParamTypeClasses #-}

    module GHC.Cmm.Reg
        ( -- * Cmm Registers
          CmmReg(..)
        , cmmRegType
        , cmmRegWidth
          -- * Local registers
        , LocalReg(..)
        , localRegType
          -- * Global registers
        , GlobalReg(..), isArgReg, globalRegSpillType, pprGlobalReg
        , spReg, hpReg, spLimReg, hpLimReg, nodeReg
        , currentTSOReg, currentNurseryReg, hpAllocReg, cccsReg
        , node, baseReg
        , GlobalRegUse(..), pprGlobalRegUse
        ) where

    import GHC.Prelude

    import GHC.Platform
    import GHC.Utils.Outputable
    import GHC.Types.Unique
    import GHC.Cmm.Type

    -----------------------------------------------------------------------------
    --              Cmm registers
    -----------------------------------------------------------------------------

    {- Note [GlobalReg vs GlobalRegUse]
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    We distinguish GlobalReg, which describes registers in the STG abstract machine,
    with GlobalRegUse, which describes an usage of such a register to store values
    of a particular CmmType.

    For example, we might want to load/store an 8-bit integer in a register that
    can store 32-bit integers.

    The width of the type must fit in the register, i.e. for a usage
    @GlobalRegUse reg ty@ we must have that

      > typeWidth ty <= typeWidth (globalRegSpillType reg)

    The restrictions about what categories of types can be stored in a given
    register are less easily stated. Some examples are:

      - Vanilla registers can contain both pointers (gcWord) and non-pointers (bWord),
        as well as sub-word sized values (e.g. b16).
      - On x86_64, SIMD registers can be used to hold vectors of both floating
        and integral values (e.g. XmmReg may store 2 Double values or 4 Int32 values).
    -}

    -- | A use of a global register at a particular type.
    --
    -- While a 'GlobalReg' identifies a global register in the STG machine,
    -- a 'GlobalRegUse' also contains information about the type we are storing
    -- in the register.
    --
    -- See Note [GlobalReg vs GlobalRegUse] for more information.
    data GlobalRegUse
      = GlobalRegUse
        { GlobalRegUse -> GlobalReg
    globalRegUseGlobalReg :: !GlobalReg
          -- ^ The underlying 'GlobalReg'
        , GlobalRegUse -> CmmType
    globalRegUseType      :: !CmmType
          -- ^ The 'CmmType' at which we are using the 'GlobalReg'.
          --
          -- Its width must be less than the width of the 'GlobalReg':
          --
          -- > typeWidth ty <= typeWidth (globalRegSpillType reg)
        }
      deriving Int -> GlobalRegUse -> ShowS
    [GlobalRegUse] -> ShowS
    GlobalRegUse -> String
    (Int -> GlobalRegUse -> ShowS)
    -> (GlobalRegUse -> String)
    -> ([GlobalRegUse] -> ShowS)
    -> Show GlobalRegUse
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> GlobalRegUse -> ShowS
    showsPrec :: Int -> GlobalRegUse -> ShowS
    $cshow :: GlobalRegUse -> String
    show :: GlobalRegUse -> String
    $cshowList :: [GlobalRegUse] -> ShowS
    showList :: [GlobalRegUse] -> ShowS
    Show

    instance Outputable GlobalRegUse where
      ppr :: GlobalRegUse -> SDoc
    ppr (GlobalRegUse GlobalReg
    reg CmmType
    _) = GlobalReg -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr GlobalReg
    reg

    pprGlobalRegUse :: IsLine doc => GlobalRegUse -> doc
    pprGlobalRegUse :: forall doc. IsLine doc => GlobalRegUse -> doc
    pprGlobalRegUse (GlobalRegUse GlobalReg
    reg CmmType
    _) = GlobalReg -> doc
    forall doc. IsLine doc => GlobalReg -> doc
    pprGlobalReg GlobalReg
    reg

    -- TODO: these instances should be removed in favour
    -- of more surgical uses of equality.
    instance Eq GlobalRegUse where
      GlobalRegUse GlobalReg
    r1 CmmType
    _ == :: GlobalRegUse -> GlobalRegUse -> Bool
    == GlobalRegUse GlobalReg
    r2 CmmType
    _ = GlobalReg
    r1 GlobalReg -> GlobalReg -> Bool
    forall a. Eq a => a -> a -> Bool
    == GlobalReg
    r2
    instance Ord GlobalRegUse where
      GlobalRegUse GlobalReg
    r1 CmmType
    _ compare :: GlobalRegUse -> GlobalRegUse -> Ordering
    `compare` GlobalRegUse GlobalReg
    r2 CmmType
    _ = GlobalReg -> GlobalReg -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare GlobalReg
    r1 GlobalReg
    r2

    data CmmReg
      = CmmLocal  {-# UNPACK #-} !LocalReg
      | CmmGlobal GlobalRegUse
      deriving ( CmmReg -> CmmReg -> Bool
    (CmmReg -> CmmReg -> Bool)
    -> (CmmReg -> CmmReg -> Bool) -> Eq CmmReg
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: CmmReg -> CmmReg -> Bool
    == :: CmmReg -> CmmReg -> Bool
    $c/= :: CmmReg -> CmmReg -> Bool
    /= :: CmmReg -> CmmReg -> Bool
    Eq, Eq CmmReg
    Eq CmmReg =>
    (CmmReg -> CmmReg -> Ordering)
    -> (CmmReg -> CmmReg -> Bool)
    -> (CmmReg -> CmmReg -> Bool)
    -> (CmmReg -> CmmReg -> Bool)
    -> (CmmReg -> CmmReg -> Bool)
    -> (CmmReg -> CmmReg -> CmmReg)
    -> (CmmReg -> CmmReg -> CmmReg)
    -> Ord CmmReg
    CmmReg -> CmmReg -> Bool
    CmmReg -> CmmReg -> Ordering
    CmmReg -> CmmReg -> CmmReg
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: CmmReg -> CmmReg -> Ordering
    compare :: CmmReg -> CmmReg -> Ordering
    $c< :: CmmReg -> CmmReg -> Bool
    < :: CmmReg -> CmmReg -> Bool
    $c<= :: CmmReg -> CmmReg -> Bool
    <= :: CmmReg -> CmmReg -> Bool
    $c> :: CmmReg -> CmmReg -> Bool
    > :: CmmReg -> CmmReg -> Bool
    $c>= :: CmmReg -> CmmReg -> Bool
    >= :: CmmReg -> CmmReg -> Bool
    $cmax :: CmmReg -> CmmReg -> CmmReg
    max :: CmmReg -> CmmReg -> CmmReg
    $cmin :: CmmReg -> CmmReg -> CmmReg
    min :: CmmReg -> CmmReg -> CmmReg
    Ord, Int -> CmmReg -> ShowS
    [CmmReg] -> ShowS
    CmmReg -> String
    (Int -> CmmReg -> ShowS)
    -> (CmmReg -> String) -> ([CmmReg] -> ShowS) -> Show CmmReg
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> CmmReg -> ShowS
    showsPrec :: Int -> CmmReg -> ShowS
    $cshow :: CmmReg -> String
    show :: CmmReg -> String
    $cshowList :: [CmmReg] -> ShowS
    showList :: [CmmReg] -> ShowS
    Show )

    instance Outputable CmmReg where
        ppr :: CmmReg -> SDoc
    ppr CmmReg
    e = CmmReg -> SDoc
    pprReg CmmReg
    e

    pprReg :: CmmReg -> SDoc
    pprReg :: CmmReg -> SDoc
    pprReg CmmReg
    r
       = case CmmReg
    r of
            CmmLocal  LocalReg
    local                   -> LocalReg -> SDoc
    pprLocalReg  LocalReg
    local
            CmmGlobal (GlobalRegUse GlobalReg
    global CmmType
    _) -> GlobalReg -> SDoc
    forall doc. IsLine doc => GlobalReg -> doc
    pprGlobalReg GlobalReg
    global

    cmmRegType :: CmmReg -> CmmType
    cmmRegType :: CmmReg -> CmmType
    cmmRegType (CmmLocal  LocalReg
    reg) = LocalReg -> CmmType
    localRegType LocalReg
    reg
    cmmRegType (CmmGlobal GlobalRegUse
    reg) = GlobalRegUse -> CmmType
    globalRegUseType GlobalRegUse
    reg

    cmmRegWidth :: CmmReg -> Width
    cmmRegWidth :: CmmReg -> Width
    cmmRegWidth = CmmType -> Width
    typeWidth (CmmType -> Width) -> (CmmReg -> CmmType) -> CmmReg -> Width
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CmmReg -> CmmType
    cmmRegType

    -----------------------------------------------------------------------------
    --              Local registers
    -----------------------------------------------------------------------------

    data LocalReg
      = LocalReg {-# UNPACK #-} !Unique !CmmType
        -- ^ Parameters:
        --   1. Identifier
        --   2. Type
      deriving Int -> LocalReg -> ShowS
    [LocalReg] -> ShowS
    LocalReg -> String
    (Int -> LocalReg -> ShowS)
    -> (LocalReg -> String) -> ([LocalReg] -> ShowS) -> Show LocalReg
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> LocalReg -> ShowS
    showsPrec :: Int -> LocalReg -> ShowS
    $cshow :: LocalReg -> String
    show :: LocalReg -> String
    $cshowList :: [LocalReg] -> ShowS
    showList :: [LocalReg] -> ShowS
    Show

    instance Eq LocalReg where
      (LocalReg Unique
    u1 CmmType
    _) == :: LocalReg -> LocalReg -> Bool
    == (LocalReg Unique
    u2 CmmType
    _) = Unique
    u1 Unique -> Unique -> Bool
    forall a. Eq a => a -> a -> Bool
    == Unique
    u2

    instance Outputable LocalReg where
        ppr :: LocalReg -> SDoc
    ppr LocalReg
    e = LocalReg -> SDoc
    pprLocalReg LocalReg
    e

    -- This is non-deterministic but we do not currently support deterministic
    -- code-generation. See Note [Unique Determinism and code generation]
    -- See Note [No Ord for Unique]
    instance Ord LocalReg where
      compare :: LocalReg -> LocalReg -> Ordering
    compare (LocalReg Unique
    u1 CmmType
    _) (LocalReg Unique
    u2 CmmType
    _) = Unique -> Unique -> Ordering
    nonDetCmpUnique Unique
    u1 Unique
    u2

    instance Uniquable LocalReg where
      getUnique :: LocalReg -> Unique
    getUnique (LocalReg Unique
    uniq CmmType
    _) = Unique
    uniq

    localRegType :: LocalReg -> CmmType
    localRegType :: LocalReg -> CmmType
    localRegType (LocalReg Unique
    _ CmmType
    rep) = CmmType
    rep

    --
    -- We only print the type of the local reg if it isn't wordRep
    --
    pprLocalReg :: LocalReg -> SDoc
    pprLocalReg :: LocalReg -> SDoc
    pprLocalReg (LocalReg Unique
    uniq CmmType
    rep) =
    --   = ppr rep <> char '_' <> ppr uniq
    -- Temp Jan08
        Char -> SDoc
    forall doc. IsLine doc => Char -> doc
    char Char
    '_' SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <> Unique -> SDoc
    forall a. Outputable a => a -> SDoc
    pprUnique Unique
    uniq SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <>
           (if CmmType -> Bool
    isWord32 CmmType
    rep -- && not (isGcPtrType rep) -- Temp Jan08               -- sigh
                        then SDoc
    dcolon SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <> SDoc
    ptr SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <> CmmType -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr CmmType
    rep
                        else SDoc
    dcolon SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <> SDoc
    ptr SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <> CmmType -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr CmmType
    rep)
       where
         pprUnique :: a -> SDoc
    pprUnique a
    unique = (SDocContext -> Bool) -> (Bool -> SDoc) -> SDoc
    forall a. (SDocContext -> a) -> (a -> SDoc) -> SDoc
    sdocOption SDocContext -> Bool
    sdocSuppressUniques ((Bool -> SDoc) -> SDoc) -> (Bool -> SDoc) -> SDoc
    forall a b. (a -> b) -> a -> b
    $ \case
           Bool
    True  -> String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "_locVar_"
           Bool
    False -> a -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr a
    unique
         ptr :: SDoc
    ptr = SDoc
    forall doc. IsOutput doc => doc
    empty
             --if isGcPtrType rep
             --      then doubleQuotes (text "ptr")
             --      else empty

    -----------------------------------------------------------------------------
    --              Global STG registers
    -----------------------------------------------------------------------------
    {-
    Note [Overlapping global registers]
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    The backend might not faithfully implement the abstraction of the STG
    machine with independent registers for different values of type
    GlobalReg. Specifically, certain pairs of registers (r1, r2) may
    overlap in the sense that a store to r1 invalidates the value in r2,
    and vice versa.

    Currently this occurs only on the x86_64 architecture where FloatReg n
    and DoubleReg n are assigned the same microarchitectural register, in
    order to allow functions to receive more Float# or Double# arguments
    in registers (as opposed to on the stack).

    There are no specific rules about which registers might overlap with
    which other registers, but presumably it's safe to assume that nothing
    will overlap with special registers like Sp or BaseReg.

    Use GHC.Cmm.Utils.regsOverlap to determine whether two GlobalRegs overlap
    on a particular platform. The instance Eq GlobalReg is syntactic
    equality of STG registers and does not take overlap into
    account. However it is still used in UserOfRegs/DefinerOfRegs and
    there are likely still bugs there, beware!
    -}

    -- | An abstract global register for the STG machine.
    --
    -- See also 'GlobalRegUse', which denotes a usage of a register at a particular
    -- type (e.g. using a 32-bit wide register to store an 8-bit wide value), as per
    -- Note [GlobalReg vs GlobalRegUse].
    data GlobalReg
      -- Argument and return registers
      = VanillaReg                  -- pointers, unboxed ints and chars
            {-# UNPACK #-} !Int     -- its number

      | FloatReg            -- single-precision floating-point registers
            {-# UNPACK #-} !Int     -- its number

      | DoubleReg           -- double-precision floating-point registers
            {-# UNPACK #-} !Int     -- its number

      | LongReg             -- long int registers (64-bit, really)
            {-# UNPACK #-} !Int     -- its number

      | XmmReg                      -- 128-bit SIMD vector register
            {-# UNPACK #-} !Int     -- its number

      | YmmReg                      -- 256-bit SIMD vector register
            {-# UNPACK #-} !Int     -- its number

      | ZmmReg                      -- 512-bit SIMD vector register
            {-# UNPACK #-} !Int     -- its number

      -- STG registers
      | Sp                  -- Stack ptr; points to last occupied stack location.
      | SpLim               -- Stack limit
      | Hp                  -- Heap ptr; points to last occupied heap location.
      | HpLim               -- Heap limit register
      | CCCS                -- Current cost-centre stack
      | CurrentTSO          -- pointer to current thread's TSO
      | CurrentNursery      -- pointer to allocation area
      | HpAlloc             -- allocation count for heap check failure

                    -- We keep the address of some commonly-called
                    -- functions in the register table, to keep code
                    -- size down:
      | EagerBlackholeInfo  -- stg_EAGER_BLACKHOLE_info
      | GCEnter1            -- stg_gc_enter_1
      | GCFun               -- stg_gc_fun

      -- Base offset for the register table, used for accessing registers
      -- which do not have real registers assigned to them.  This register
      -- will only appear after we have expanded GlobalReg into memory accesses
      -- (where necessary) in the native code generator.
      | BaseReg

      -- The register used by the platform for the C stack pointer. This is
      -- a break in the STG abstraction used exclusively to setup stack unwinding
      -- information.
      | MachSp

      -- The is a dummy register used to indicate to the stack unwinder where
      -- a routine would return to.
      | UnwindReturnReg

      -- Base Register for PIC (position-independent code) calculations
      -- Only used inside the native code generator. It's exact meaning differs
      -- from platform to platform (see module PositionIndependentCode).
      | PicBaseReg

      deriving( GlobalReg -> GlobalReg -> Bool
    (GlobalReg -> GlobalReg -> Bool)
    -> (GlobalReg -> GlobalReg -> Bool) -> Eq GlobalReg
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: GlobalReg -> GlobalReg -> Bool
    == :: GlobalReg -> GlobalReg -> Bool
    $c/= :: GlobalReg -> GlobalReg -> Bool
    /= :: GlobalReg -> GlobalReg -> Bool
    Eq, Eq GlobalReg
    Eq GlobalReg =>
    (GlobalReg -> GlobalReg -> Ordering)
    -> (GlobalReg -> GlobalReg -> Bool)
    -> (GlobalReg -> GlobalReg -> Bool)
    -> (GlobalReg -> GlobalReg -> Bool)
    -> (GlobalReg -> GlobalReg -> Bool)
    -> (GlobalReg -> GlobalReg -> GlobalReg)
    -> (GlobalReg -> GlobalReg -> GlobalReg)
    -> Ord GlobalReg
    GlobalReg -> GlobalReg -> Bool
    GlobalReg -> GlobalReg -> Ordering
    GlobalReg -> GlobalReg -> GlobalReg
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: GlobalReg -> GlobalReg -> Ordering
    compare :: GlobalReg -> GlobalReg -> Ordering
    $c< :: GlobalReg -> GlobalReg -> Bool
    < :: GlobalReg -> GlobalReg -> Bool
    $c<= :: GlobalReg -> GlobalReg -> Bool
    <= :: GlobalReg -> GlobalReg -> Bool
    $c> :: GlobalReg -> GlobalReg -> Bool
    > :: GlobalReg -> GlobalReg -> Bool
    $c>= :: GlobalReg -> GlobalReg -> Bool
    >= :: GlobalReg -> GlobalReg -> Bool
    $cmax :: GlobalReg -> GlobalReg -> GlobalReg
    max :: GlobalReg -> GlobalReg -> GlobalReg
    $cmin :: GlobalReg -> GlobalReg -> GlobalReg
    min :: GlobalReg -> GlobalReg -> GlobalReg
    Ord, Int -> GlobalReg -> ShowS
    [GlobalReg] -> ShowS
    GlobalReg -> String
    (Int -> GlobalReg -> ShowS)
    -> (GlobalReg -> String)
    -> ([GlobalReg] -> ShowS)
    -> Show GlobalReg
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> GlobalReg -> ShowS
    showsPrec :: Int -> GlobalReg -> ShowS
    $cshow :: GlobalReg -> String
    show :: GlobalReg -> String
    $cshowList :: [GlobalReg] -> ShowS
    showList :: [GlobalReg] -> ShowS
    Show )
        -- NOTE: the Ord instance affects the tuple layout in GHCi, see
        --       Note [GHCi and native call registers]

    instance Outputable GlobalReg where
        ppr :: GlobalReg -> SDoc
    ppr GlobalReg
    e = GlobalReg -> SDoc
    forall doc. IsLine doc => GlobalReg -> doc
    pprGlobalReg GlobalReg
    e

    instance OutputableP env GlobalReg where
        pdoc :: env -> GlobalReg -> SDoc
    pdoc env
    _ = GlobalReg -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr

    pprGlobalReg :: IsLine doc => GlobalReg -> doc
    pprGlobalReg :: forall doc. IsLine doc => GlobalReg -> doc
    pprGlobalReg GlobalReg
    gr
        = case GlobalReg
    gr of
            VanillaReg Int
    n   -> Char -> doc
    forall doc. IsLine doc => Char -> doc
    char Char
    'R' doc -> doc -> doc
    forall doc. IsLine doc => doc -> doc -> doc
    <> Int -> doc
    forall doc. IsLine doc => Int -> doc
    int Int
    n
            FloatReg   Int
    n   -> Char -> doc
    forall doc. IsLine doc => Char -> doc
    char Char
    'F' doc -> doc -> doc
    forall doc. IsLine doc => doc -> doc -> doc
    <> Int -> doc
    forall doc. IsLine doc => Int -> doc
    int Int
    n
            DoubleReg  Int
    n   -> Char -> doc
    forall doc. IsLine doc => Char -> doc
    char Char
    'D' doc -> doc -> doc
    forall doc. IsLine doc => doc -> doc -> doc
    <> Int -> doc
    forall doc. IsLine doc => Int -> doc
    int Int
    n
            LongReg    Int
    n   -> Char -> doc
    forall doc. IsLine doc => Char -> doc
    char Char
    'L' doc -> doc -> doc
    forall doc. IsLine doc => doc -> doc -> doc
    <> Int -> doc
    forall doc. IsLine doc => Int -> doc
    int Int
    n
            XmmReg     Int
    n   -> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "XMM" doc -> doc -> doc
    forall doc. IsLine doc => doc -> doc -> doc
    <> Int -> doc
    forall doc. IsLine doc => Int -> doc
    int Int
    n
            YmmReg     Int
    n   -> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "YMM" doc -> doc -> doc
    forall doc. IsLine doc => doc -> doc -> doc
    <> Int -> doc
    forall doc. IsLine doc => Int -> doc
    int Int
    n
            ZmmReg     Int
    n   -> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "ZMM" doc -> doc -> doc
    forall doc. IsLine doc => doc -> doc -> doc
    <> Int -> doc
    forall doc. IsLine doc => Int -> doc
    int Int
    n
            GlobalReg
    Sp             -> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "Sp"
            GlobalReg
    SpLim          -> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "SpLim"
            GlobalReg
    Hp             -> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "Hp"
            GlobalReg
    HpLim          -> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "HpLim"
            GlobalReg
    MachSp         -> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "MachSp"
            GlobalReg
    UnwindReturnReg-> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "UnwindReturnReg"
            GlobalReg
    CCCS           -> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "CCCS"
            GlobalReg
    CurrentTSO     -> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "CurrentTSO"
            GlobalReg
    CurrentNursery -> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "CurrentNursery"
            GlobalReg
    HpAlloc        -> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "HpAlloc"
            GlobalReg
    EagerBlackholeInfo -> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "stg_EAGER_BLACKHOLE_info"
            GlobalReg
    GCEnter1       -> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "stg_gc_enter_1"
            GlobalReg
    GCFun          -> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "stg_gc_fun"
            GlobalReg
    BaseReg        -> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "BaseReg"
            GlobalReg
    PicBaseReg     -> String -> doc
    forall doc. IsLine doc => String -> doc
    text String
    "PicBaseReg"
    {-# SPECIALIZE pprGlobalReg :: GlobalReg -> SDoc #-}
    {-# SPECIALIZE pprGlobalReg :: GlobalReg -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable

    -- convenient aliases
    baseReg, spReg, hpReg, spLimReg, hpLimReg, nodeReg,
      currentTSOReg, currentNurseryReg, hpAllocReg, cccsReg :: Platform -> CmmReg
    baseReg :: Platform -> CmmReg
    baseReg           Platform
    p = GlobalRegUse -> CmmReg
    CmmGlobal (GlobalReg -> CmmType -> GlobalRegUse
    GlobalRegUse GlobalReg
    BaseReg        (CmmType -> GlobalRegUse) -> CmmType -> GlobalRegUse
    forall a b. (a -> b) -> a -> b
    $ Platform -> CmmType
    bWord Platform
    p)
    spReg :: Platform -> CmmReg
    spReg             Platform
    p = GlobalRegUse -> CmmReg
    CmmGlobal (GlobalReg -> CmmType -> GlobalRegUse
    GlobalRegUse GlobalReg
    Sp             (CmmType -> GlobalRegUse) -> CmmType -> GlobalRegUse
    forall a b. (a -> b) -> a -> b
    $ Platform -> CmmType
    bWord Platform
    p)
    hpReg :: Platform -> CmmReg
    hpReg             Platform
    p = GlobalRegUse -> CmmReg
    CmmGlobal (GlobalReg -> CmmType -> GlobalRegUse
    GlobalRegUse GlobalReg
    Hp             (CmmType -> GlobalRegUse) -> CmmType -> GlobalRegUse
    forall a b. (a -> b) -> a -> b
    $ Platform -> CmmType
    gcWord Platform
    p)
    hpLimReg :: Platform -> CmmReg
    hpLimReg          Platform
    p = GlobalRegUse -> CmmReg
    CmmGlobal (GlobalReg -> CmmType -> GlobalRegUse
    GlobalRegUse GlobalReg
    HpLim          (CmmType -> GlobalRegUse) -> CmmType -> GlobalRegUse
    forall a b. (a -> b) -> a -> b
    $ Platform -> CmmType
    bWord Platform
    p)
    spLimReg :: Platform -> CmmReg
    spLimReg          Platform
    p = GlobalRegUse -> CmmReg
    CmmGlobal (GlobalReg -> CmmType -> GlobalRegUse
    GlobalRegUse GlobalReg
    SpLim          (CmmType -> GlobalRegUse) -> CmmType -> GlobalRegUse
    forall a b. (a -> b) -> a -> b
    $ Platform -> CmmType
    bWord Platform
    p)
    nodeReg :: Platform -> CmmReg
    nodeReg           Platform
    p = GlobalRegUse -> CmmReg
    CmmGlobal (GlobalReg -> CmmType -> GlobalRegUse
    GlobalRegUse (Int -> GlobalReg
    VanillaReg Int
    1) (CmmType -> GlobalRegUse) -> CmmType -> GlobalRegUse
    forall a b. (a -> b) -> a -> b
    $ Platform -> CmmType
    gcWord Platform
    p)
    currentTSOReg :: Platform -> CmmReg
    currentTSOReg     Platform
    p = GlobalRegUse -> CmmReg
    CmmGlobal (GlobalReg -> CmmType -> GlobalRegUse
    GlobalRegUse GlobalReg
    CurrentTSO     (CmmType -> GlobalRegUse) -> CmmType -> GlobalRegUse
    forall a b. (a -> b) -> a -> b
    $ Platform -> CmmType
    bWord Platform
    p)
    currentNurseryReg :: Platform -> CmmReg
    currentNurseryReg Platform
    p = GlobalRegUse -> CmmReg
    CmmGlobal (GlobalReg -> CmmType -> GlobalRegUse
    GlobalRegUse GlobalReg
    CurrentNursery (CmmType -> GlobalRegUse) -> CmmType -> GlobalRegUse
    forall a b. (a -> b) -> a -> b
    $ Platform -> CmmType
    bWord Platform
    p)
    hpAllocReg :: Platform -> CmmReg
    hpAllocReg        Platform
    p = GlobalRegUse -> CmmReg
    CmmGlobal (GlobalReg -> CmmType -> GlobalRegUse
    GlobalRegUse GlobalReg
    HpAlloc        (CmmType -> GlobalRegUse) -> CmmType -> GlobalRegUse
    forall a b. (a -> b) -> a -> b
    $ Platform -> CmmType
    bWord Platform
    p)
    cccsReg :: Platform -> CmmReg
    cccsReg           Platform
    p = GlobalRegUse -> CmmReg
    CmmGlobal (GlobalReg -> CmmType -> GlobalRegUse
    GlobalRegUse GlobalReg
    CCCS           (CmmType -> GlobalRegUse) -> CmmType -> GlobalRegUse
    forall a b. (a -> b) -> a -> b
    $ Platform -> CmmType
    bWord Platform
    p)

    node :: GlobalReg
    node :: GlobalReg
    node = Int -> GlobalReg
    VanillaReg Int
    1

    globalRegSpillType :: Platform -> GlobalReg -> CmmType
    globalRegSpillType :: Platform -> GlobalReg -> CmmType
    globalRegSpillType Platform
    platform = \case
       VanillaReg Int
    _ -> Platform -> CmmType
    gcWord Platform
    platform
       FloatReg   Int
    _ -> Width -> CmmType
    cmmFloat Width
    W32
       DoubleReg  Int
    _ -> Width -> CmmType
    cmmFloat Width
    W64
       LongReg    Int
    _ -> Width -> CmmType
    cmmBits  Width
    W64

       -- TODO: improve the internal model of SIMD/vectorized registers
       -- the right design SHOULD improve handling of float and double code too.
       -- see remarks in Note [SIMD Design for the future] in GHC.StgToCmm.Prim
       XmmReg    Int
    _ -> Int -> CmmType -> CmmType
    cmmVec  Int
    4 (Width -> CmmType
    cmmBits Width
    W32)
       YmmReg    Int
    _ -> Int -> CmmType -> CmmType
    cmmVec  Int
    8 (Width -> CmmType
    cmmBits Width
    W32)
       ZmmReg    Int
    _ -> Int -> CmmType -> CmmType
    cmmVec Int
    16 (Width -> CmmType
    cmmBits Width
    W32)

       GlobalReg
    Hp          -> Platform -> CmmType
    gcWord Platform
    platform -- The initialiser for all
                                      -- dynamically allocated closures
       GlobalReg
    _           -> Platform -> CmmType
    bWord Platform
    platform

    isArgReg :: GlobalReg -> Bool
    isArgReg :: GlobalReg -> Bool
    isArgReg (VanillaReg {}) = Bool
    True
    isArgReg (FloatReg {})   = Bool
    True
    isArgReg (DoubleReg {})  = Bool
    True
    isArgReg (LongReg {})    = Bool
    True
    isArgReg (XmmReg {})     = Bool
    True
    isArgReg (YmmReg {})     = Bool
    True
    isArgReg (ZmmReg {})     = Bool
    True
    isArgReg GlobalReg
    _               = Bool
    False