ghc-9.12.1: GHC/Platform/Reg.hs
{-# LANGUAGE MagicHash #-}
-- | An architecture independent description of a register.
-- This needs to stay architecture independent because it is used
-- by NCGMonad and the register allocators, which are shared
-- by all architectures.
--
module GHC.Platform.Reg (
RegNo,
Reg(..),
regSingle,
realRegSingle,
isRealReg, takeRealReg,
isVirtualReg, takeVirtualReg,
VirtualReg(..),
renameVirtualReg,
classOfVirtualReg,
getHiVirtualRegFromLo,
getHiVRegFromLo,
RealReg(..),
regNosOfRealReg,
realRegsAlias,
liftPatchFnToRegReg
)
where
import GHC.Prelude
import GHC.Exts ( Int(I#), dataToTag# )
import GHC.Utils.Outputable
import GHC.Utils.Panic
import GHC.Types.Unique
import GHC.Builtin.Uniques
import GHC.Platform.Reg.Class
import qualified GHC.Platform.Reg.Class.Unified as Unified
import qualified GHC.Platform.Reg.Class.Separate as Separate
import qualified GHC.Platform.Reg.Class.NoVectors as NoVectors
import GHC.Platform.ArchOS
-- | An identifier for a primitive real machine register.
type RegNo
= Int
-- VirtualRegs are virtual registers. The register allocator will
-- eventually have to map them into RealRegs, or into spill slots.
--
-- VirtualRegs are allocated on the fly, usually to represent a single
-- value in the abstract assembly code (i.e. dynamic registers are
-- usually single assignment).
--
-- The single assignment restriction isn't necessary to get correct code,
-- although a better register allocation will result if single
-- assignment is used -- because the allocator maps a VirtualReg into
-- a single RealReg, even if the VirtualReg has multiple live ranges.
--
-- Virtual regs can be of either class, so that info is attached.
--
data VirtualReg
-- | Integer virtual register
= VirtualRegI { virtualRegUnique :: {-# UNPACK #-} !Unique }
-- | High part of 2-word virtual register
| VirtualRegHi { virtualRegUnique :: {-# UNPACK #-} !Unique }
-- | Double virtual register
| VirtualRegD { virtualRegUnique :: {-# UNPACK #-} !Unique }
-- | 128-bit wide vector virtual register
| VirtualRegV128 { virtualRegUnique :: {-# UNPACK #-} !Unique }
deriving (Eq, Show)
-- We can't derive Ord, because Unique doesn't have an Ord instance.
-- Note nonDetCmpUnique in the implementation. See Note [No Ord for Unique].
-- This is non-deterministic but we do not currently support deterministic
-- code-generation. See Note [Unique Determinism and code generation]
instance Ord VirtualReg where
compare vr1 vr2 =
case compare (I# (dataToTag# vr1)) (I# (dataToTag# vr2)) of
LT -> LT
GT -> GT
EQ -> nonDetCmpUnique (virtualRegUnique vr1) (virtualRegUnique vr2)
instance Uniquable VirtualReg where
getUnique = virtualRegUnique
instance Outputable VirtualReg where
ppr reg
= case reg of
VirtualRegI u -> text "%vI_" <> pprUniqueAlways u
VirtualRegHi u -> text "%vHi_" <> pprUniqueAlways u
VirtualRegD u -> text "%vDouble_" <> pprUniqueAlways u
VirtualRegV128 u -> text "%vV128_" <> pprUniqueAlways u
renameVirtualReg :: Unique -> VirtualReg -> VirtualReg
renameVirtualReg u r = r { virtualRegUnique = u }
classOfVirtualReg :: Arch -> VirtualReg -> RegClass
classOfVirtualReg arch vr
= case vr of
VirtualRegI{} ->
case regArch of
Unified -> Unified.RcInteger
Separate -> Separate.RcInteger
NoVectors -> NoVectors.RcInteger
VirtualRegHi{} ->
case regArch of
Unified -> Unified.RcInteger
Separate -> Separate.RcInteger
NoVectors -> NoVectors.RcInteger
VirtualRegD{} ->
case regArch of
Unified -> Unified.RcFloatOrVector
Separate -> Separate.RcFloat
NoVectors -> NoVectors.RcFloat
VirtualRegV128{} ->
case regArch of
Unified -> Unified.RcFloatOrVector
Separate -> Separate.RcVector
NoVectors -> pprPanic "classOfVirtualReg VirtualRegV128"
( text "arch:" <+> text ( show arch ) )
where
regArch = registerArch arch
-- Determine the upper-half vreg for a 64-bit quantity on a 32-bit platform
-- when supplied with the vreg for the lower-half of the quantity.
-- (NB. Not reversible).
getHiVirtualRegFromLo :: VirtualReg -> VirtualReg
getHiVirtualRegFromLo reg
= case reg of
-- makes a pseudo-unique with tag 'H'
VirtualRegI u -> VirtualRegHi (newTagUnique u 'H')
_ -> panic "Reg.getHiVirtualRegFromLo"
getHiVRegFromLo :: Reg -> Reg
getHiVRegFromLo reg
= case reg of
RegVirtual vr -> RegVirtual (getHiVirtualRegFromLo vr)
RegReal _ -> panic "Reg.getHiVRegFromLo"
------------------------------------------------------------------------------------
-- | RealRegs are machine regs which are available for allocation, in
-- the usual way. We know what class they are, because that's part of
-- the processor's architecture.
--
newtype RealReg
= RealRegSingle RegNo
deriving (Eq, Show, Ord)
instance Uniquable RealReg where
getUnique reg
= case reg of
RealRegSingle i -> mkRegSingleUnique i
instance Outputable RealReg where
ppr reg
= case reg of
RealRegSingle i -> text "%r" <> int i
regNosOfRealReg :: RealReg -> [RegNo]
regNosOfRealReg rr
= case rr of
RealRegSingle r1 -> [r1]
realRegsAlias :: RealReg -> RealReg -> Bool
realRegsAlias rr1 rr2 =
-- used to be `not $ null $ intersect (regNosOfRealReg rr1) (regNosOfRealReg rr2)`
-- but that resulted in some gnarly, gnarly, allocating code. So we manually
-- write out all the cases which gives us nice non-allocating code.
case rr1 of
RealRegSingle r1 ->
case rr2 of RealRegSingle r2 -> r1 == r2
--------------------------------------------------------------------------------
-- | A register, either virtual or real
data Reg
= RegVirtual !VirtualReg
| RegReal !RealReg
deriving (Eq, Ord, Show)
regSingle :: RegNo -> Reg
regSingle regNo = RegReal (realRegSingle regNo)
realRegSingle :: RegNo -> RealReg
realRegSingle regNo = RealRegSingle regNo
-- We like to have Uniques for Reg so that we can make UniqFM and UniqSets
-- in the register allocator.
instance Uniquable Reg where
getUnique reg
= case reg of
RegVirtual vr -> getUnique vr
RegReal rr -> getUnique rr
-- | Print a reg in a generic manner
-- If you want the architecture specific names, then use the pprReg
-- function from the appropriate Ppr module.
instance Outputable Reg where
ppr reg
= case reg of
RegVirtual vr -> ppr vr
RegReal rr -> ppr rr
isRealReg :: Reg -> Bool
isRealReg reg
= case reg of
RegReal _ -> True
RegVirtual _ -> False
takeRealReg :: Reg -> Maybe RealReg
takeRealReg reg
= case reg of
RegReal rr -> Just rr
_ -> Nothing
isVirtualReg :: Reg -> Bool
isVirtualReg reg
= case reg of
RegReal _ -> False
RegVirtual _ -> True
takeVirtualReg :: Reg -> Maybe VirtualReg
takeVirtualReg reg
= case reg of
RegReal _ -> Nothing
RegVirtual vr -> Just vr
-- | The patch function supplied by the allocator maps VirtualReg to RealReg
-- regs, but sometimes we want to apply it to plain old Reg.
--
liftPatchFnToRegReg :: (VirtualReg -> RealReg) -> (Reg -> Reg)
liftPatchFnToRegReg patchF reg
= case reg of
RegVirtual vr -> RegReal (patchF vr)
RegReal _ -> reg