Commit 665229e5 authored by sewardj's avatar sewardj

[project @ 2000-06-15 08:38:25 by sewardj]

Major thing: new register allocator.  Brief description follows.
Should correctly handle code with loops in, even though we don't
generate any such at the moment.  A lot of comments.  The previous
machinery for spilling is retained, as is the idea of a fast-and-easy
initial allocation attempt intended to deal with the majority of code
blocks (about 60% on x86) very cheaply.  Many comments explaining
in detail how it works :-)

The Stix inliner is now on by default.  Integer code seems to run
within about 1% of that -fvia-C.  x86 fp code is significantly worse,
up to about 30% slower, depending on the amount of fp activity.

Minor thing: lazyfication of the top-level NCG plumbing, so that the
NCG doesn't require any greater residency than compiling to C, just a
bit more time.  Created lazyThenUs and lazyMapUs for this purpose.

The new allocator is somewhat, although not catastophically, slower
than the old one.  Fixing of the long-standing NCG space leak more
than makes up for it; overall hsc run-time is down about 5%, due to
significantly reduced GC time.

--------------------------------------------------------------------

Instructions are numbered sequentially, starting at zero.

A flow edge (FE) is a pair of insn numbers (MkFE Int Int) denoting
a possible flow of control from the first insn to the second.

The input to the register allocator is a list of instructions, which
mention Regs.  A Reg can be a RealReg -- a real machine reg -- or a
VirtualReg, which carries a unique.  After allocation, all the
VirtualReg references will have been converted into RealRegs, and
possibly some spill code will have been inserted.

The heart of the register allocator works in four phases.

1.  (find_flow_edges) Calculate all the FEs for the code list.
    Return them not as a [FE], but implicitly, as a pair of
    Array Int [Int], being the successor and predecessor maps
    for instructions.

2.  (calc_liveness) Returns a FiniteMap FE RegSet.  For each
    FE, indicates the set of registers live on that FE.  Note
    that the set includes both RealRegs and VirtualRegs.  The
    former appear because the code could mention fixed register
    usages, and we need to take them into account from the start.

3.  (calc_live_range_sets) Invert the above mapping, giving a
    FiniteMap Reg FeSet, indicating, for each virtual and real
    reg mentioned in the code, which FEs it is live on.

4.  (calc_vreg_to_rreg_mapping) For virtual reg, try and find
    an allocatable real register for it.  Each real register has
    a "current commitment", indicating the set of FEs it is
    currently live on.  A virtual reg v can be assigned to
    real reg r iff v's live-fe-set does not intersect with r's
    current commitment fe-set.  If the assignment is made,
    v's live-fe-set is union'd into r's current commitment fe-set.
    There is also the minor restriction that v and r must be of
    the same register class (integer or floating).

    Once this mapping is established, we simply apply it to the
    input insns, and that's it.

    If no suitable real register can be found, the vreg is mapped
    to itself, and we deem allocation to have failed.  The partially
    allocated code is returned.  The higher echelons of the allocator
    (doGeneralAlloc and runRegAlloc) then cooperate to insert spill
    code and re-run allocation, until a successful allocation is found.
parent 1364aa0b
......@@ -15,6 +15,7 @@ module UniqSupply (
getUniqueUs, getUniquesUs,
mapUs, mapAndUnzipUs, mapAndUnzip3Us,
thenMaybeUs, mapAccumLUs,
lazyThenUs, lazyMapUs,
mkSplitUniqSupply,
splitUniqSupply
......@@ -121,6 +122,7 @@ initUs_ :: UniqSupply -> UniqSM a -> a
initUs_ init_us m = case m init_us of { (r,us) -> r }
{-# INLINE thenUs #-}
{-# INLINE lazyThenUs #-}
{-# INLINE returnUs #-}
{-# INLINE splitUniqSupply #-}
\end{code}
......@@ -135,10 +137,15 @@ thenUs :: UniqSM a -> (a -> UniqSM b) -> UniqSM b
thenUs expr cont us
= case (expr us) of { (result, us') -> cont result us' }
lazyThenUs :: UniqSM a -> (a -> UniqSM b) -> UniqSM b
lazyThenUs expr cont us
= let (result, us') = expr us in cont result us'
thenUs_ :: UniqSM a -> UniqSM b -> UniqSM b
thenUs_ expr cont us
= case (expr us) of { (_, us') -> cont us' }
returnUs :: a -> UniqSM a
returnUs result us = (result, us)
......@@ -159,13 +166,19 @@ getUniquesUs n us = case splitUniqSupply us of
\begin{code}
mapUs :: (a -> UniqSM b) -> [a] -> UniqSM [b]
mapUs f [] = returnUs []
mapUs f (x:xs)
= f x `thenUs` \ r ->
mapUs f xs `thenUs` \ rs ->
returnUs (r:rs)
lazyMapUs :: (a -> UniqSM b) -> [a] -> UniqSM [b]
lazyMapUs f [] = returnUs []
lazyMapUs f (x:xs)
= f x `lazyThenUs` \ r ->
lazyMapUs f xs `lazyThenUs` \ rs ->
returnUs (r:rs)
mapAndUnzipUs :: (a -> UniqSM (b,c)) -> [a] -> UniqSM ([b],[c])
mapAndUnzip3Us :: (a -> UniqSM (b,c,d)) -> [a] -> UniqSM ([b],[c],[d])
......
......@@ -467,8 +467,10 @@ mkPseudoUnique1, mkPseudoUnique2, mkPseudoUnique3,
mkBuiltinUnique i = mkUnique 'B' i
mkPseudoUnique1 i = mkUnique 'C' i -- used for getUnique on Regs
mkPseudoUnique2 i = mkUnique 'D' i -- ditto
mkPseudoUnique3 i = mkUnique 'E' i -- ditto
mkPseudoUnique2 i = mkUnique 'D' i -- used in NCG for getUnique on RealRegs
mkPseudoUnique3 i = mkUnique 'E' i -- used in NCG spiller to create spill VirtualRegs
getBuiltinUniques :: Int -> [Unique]
getBuiltinUniques n = map (mkUnique 'B') [1 .. n]
......
......@@ -32,7 +32,7 @@ import CmdLineOpts
import Maybes ( maybeToBool )
import ErrUtils ( doIfSet, dumpIfSet )
import Outputable
import IO ( IOMode(..), hClose, openFile )
import IO ( IOMode(..), hClose, openFile, Handle )
\end{code}
......@@ -69,6 +69,7 @@ codeOutput mod_name tycons classes core_binds stg_binds
} }
doOutput :: (Handle -> IO ()) -> IO ()
doOutput io_action
= (do handle <- openFile opt_OutputFile WriteMode
io_action handle
......@@ -103,7 +104,7 @@ outputAsm flat_absC ncg_uniqs
= do dumpIfSet opt_D_dump_stix "Final stix code" stix_final
dumpIfSet opt_D_dump_asm "Asm code" ncg_output_d
doOutput (\ f -> printForAsm f ncg_output_d)
doOutput ( \f -> printForAsm f ncg_output_d)
where
(stix_final, ncg_output_d) = nativeCodeGen flat_absC ncg_uniqs
......
......@@ -14,7 +14,7 @@ import Stix
import MachMisc
import AbsCUtils ( getAmodeRep, mixedTypeLocn,
nonemptyAbsC, mkAbsCStmts, mkAbsCStmtList
nonemptyAbsC, mkAbsCStmts
)
import PprAbsC ( dumpRealC )
import SMRep ( fixedItblSize,
......@@ -54,11 +54,10 @@ We leave the chunks separated so that register allocation can be
performed locally within the chunk.
\begin{code}
genCodeAbstractC :: AbstractC -> UniqSM [[StixTree]]
genCodeAbstractC :: AbstractC -> UniqSM [StixTree]
genCodeAbstractC absC
= mapUs gentopcode (mkAbsCStmtList absC) `thenUs` \ trees ->
returnUs ([StComment SLIT("Native Code")] : trees)
= gentopcode absC
where
a2stix = amodeToStix
a2stix' = amodeToStix'
......
......@@ -18,9 +18,10 @@ import PprMach
import AbsCStixGen ( genCodeAbstractC )
import AbsCSyn ( AbstractC, MagicId )
import AbsCUtils ( mkAbsCStmtList )
import AsmRegAlloc ( runRegAllocate )
import PrimOp ( commutableOp, PrimOp(..) )
import RegAllocInfo ( mkMRegsState, MRegsState, findReservedRegs )
import RegAllocInfo ( findReservedRegs )
import Stix ( StixTree(..), StixReg(..),
pprStixTrees, pprStixTree, CodeSegment(..),
stixCountTempUses, stixSubst,
......@@ -29,7 +30,8 @@ import Stix ( StixTree(..), StixReg(..),
uniqOfNatM_State, deltaOfNatM_State )
import PrimRep ( isFloatingRep, PrimRep(..) )
import UniqSupply ( returnUs, thenUs, mapUs, initUs,
initUs_, UniqSM, UniqSupply )
initUs_, UniqSM, UniqSupply,
lazyThenUs, lazyMapUs )
import MachMisc ( IF_ARCH_i386(i386_insert_ffrees,) )
import OrdList ( fromOL, concatOL )
......@@ -87,38 +89,47 @@ So, here we go:
\begin{code}
nativeCodeGen :: AbstractC -> UniqSupply -> (SDoc, SDoc)
nativeCodeGen absC us
= let (stixRaw, us1) = initUs us (genCodeAbstractC absC)
stixOpt = map genericOpt stixRaw
insns = initUs_ us1 (codeGen stixOpt)
debug_stix = vcat (map pprStixTrees stixOpt)
in {- trace "nativeGen: begin" -} (debug_stix, insns)
\end{code}
= let absCstmts = mkAbsCStmtList absC
(sdoc_pairs, us1) = initUs us (lazyMapUs absCtoNat absCstmts)
stix_sdocs = map fst sdoc_pairs
insn_sdocs = map snd sdoc_pairs
@codeGen@ is the top-level code-generation function:
\begin{code}
codeGen :: [[StixTree]] -> UniqSM SDoc
codeGen stixFinal
= mapUs genMachCode stixFinal `thenUs` \ dynamic_codes ->
let
fp_kludge :: [Instr] -> [Instr]
fp_kludge = IF_ARCH_i386(i386_insert_ffrees,id)
static_instrss :: [[Instr]]
static_instrss = map fp_kludge (scheduleMachCode dynamic_codes)
docs = map (vcat . map pprInstr) static_instrss
-- for debugging only
docs_prealloc = map (vcat . map pprInstr . fromOL)
dynamic_codes
text_prealloc = vcat (intersperse (char ' ' $$ char ' ') docs_prealloc)
in
--trace (showSDoc text_prealloc) (
returnUs (vcat (intersperse (char ' '
insn_sdoc = my_vcat insn_sdocs
stix_sdoc = vcat stix_sdocs
# if DEBUG
my_trace m x = trace m x
my_vcat sds = vcat (intersperse (char ' '
$$ ptext SLIT("# ___stg_split_marker")
$$ char ' ')
docs))
--)
sds)
# else
my_vcat sds = vcat sds
my_trace m x = x
# endif
in
my_trace "nativeGen: begin"
(stix_sdoc, insn_sdoc)
absCtoNat :: AbstractC -> UniqSM (SDoc, SDoc)
absCtoNat absC
= genCodeAbstractC absC `thenUs` \ stixRaw ->
genericOpt stixRaw `bind` \ stixOpt ->
genMachCode stixOpt `thenUs` \ pre_regalloc ->
regAlloc pre_regalloc `bind` \ almost_final ->
x86fp_kludge almost_final `bind` \ final_mach_code ->
vcat (map pprInstr final_mach_code) `bind` \ final_sdoc ->
pprStixTrees stixOpt `bind` \ stix_sdoc ->
returnUs (stix_sdoc, final_sdoc)
where
bind f x = x f
x86fp_kludge :: [Instr] -> [Instr]
x86fp_kludge = IF_ARCH_i386(i386_insert_ffrees,id)
regAlloc :: InstrBlock -> [Instr]
regAlloc = runRegAllocate allocatableRegs findReservedRegs
\end{code}
Top level code generator for a chunk of stix code. For this part of
......@@ -154,20 +165,6 @@ genMachCode stmts initial_us
(int final_delta)
\end{code}
The next bit does the code scheduling. The scheduler must also deal
with register allocation of temporaries. Much parallelism can be
exposed via the OrdList, but more might occur, so further analysis
might be needed.
\begin{code}
scheduleMachCode :: [InstrBlock] -> [[Instr]]
scheduleMachCode
= map (runRegAllocate freeRegsState findReservedRegs)
where
freeRegsState = mkMRegsState (extractMappedRegNos freeRegs)
\end{code}
%************************************************************************
%* *
\subsection[NCOpt]{The Generic Optimiser}
......@@ -197,24 +194,26 @@ stixPeep :: [StixTree] -> [StixTree]
-- second assignment would be substituted for, giving nonsense
-- code. As far as I can see, StixTemps are only ever assigned
-- to once. It would be nice to be sure!
{-
stixPeep ( t1@(StAssign pka (StReg (StixTemp u pk)) rhs)
: t2
: ts )
| stixCountTempUses u t2 == 1
&& sum (map (stixCountTempUses u) ts) == 0
= trace ("nativeGen: stixInline: " ++ showSDoc (pprStixTree rhs))
=
# ifdef DEBUG
trace ("nativeGen: inlining " ++ showSDoc (pprStixTree rhs))
# endif
(stixPeep (stixSubst u rhs t2 : ts))
stixPeep (t1:t2:ts) = t1 : stixPeep (t2:ts)
stixPeep [t1] = [t1]
stixPeep [] = []
-}
-- disable stix inlining until we figure out how to fix the
-- latent bugs in the register allocator which are exposed by
-- the inliner.
stixPeep = id
--stixPeep = id
\end{code}
For most nodes, just optimize the children.
......
This diff is collapsed.
......@@ -241,7 +241,7 @@ getRegister (StReg (StixMagicId stgreg))
-- cannae be Nothing
getRegister (StReg (StixTemp u pk))
= returnNat (Fixed pk (UnmappedReg u pk) nilOL)
= returnNat (Fixed pk (mkVReg u pk) nilOL)
getRegister tree@(StIndex _ _ _) = getRegister (mangleIndexTree tree)
......
......@@ -14,25 +14,21 @@ modules --- the pleasure has been foregone.)
module MachRegs (
Reg(..),
RegClass(..), regClass,
Reg(..), isRealReg, isVirtualReg,
allocatableRegs,
Imm(..),
MachRegsAddr(..),
RegLoc(..),
RegNo,
addrOffset,
argRegs,
baseRegOffset,
callClobberedRegs,
callerSaves,
extractMappedRegNos,
mappedRegNo,
freeMappedRegs,
freeReg, freeRegs,
freeReg,
getNewRegNCG,
mkVReg,
magicIdRegMaybe,
mkReg,
realReg,
saveLoc,
spRel,
stgReg,
......@@ -63,13 +59,10 @@ import AbsCSyn ( MagicId(..) )
import AbsCUtils ( magicIdPrimRep )
import CLabel ( CLabel, mkMainRegTableLabel )
import PrimOp ( PrimOp(..) )
import PrimRep ( PrimRep(..) )
import PrimRep ( PrimRep(..), isFloatingRep )
import Stix ( StixTree(..), StixReg(..),
getUniqueNat, returnNat, thenNat, NatM )
import Unique ( mkPseudoUnique1, mkPseudoUnique2, mkPseudoUnique3,
Uniquable(..), Unique
)
--import UniqSupply ( getUniqueUs, returnUs, thenUs, UniqSM )
import Unique ( mkPseudoUnique2, Uniquable(..), Unique )
import Outputable
\end{code}
......@@ -249,101 +242,78 @@ fpRel n
%* *
%************************************************************************
Static Registers correspond to actual machine registers. These should
be avoided until the last possible moment.
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.
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). With the new register allocator, 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.
Dynamic registers are allocated on the fly, usually to represent a single
value in the abstract assembly code (i.e. dynamic registers are usually
single assignment). Ultimately, they are mapped to available machine
registers before spitting out the code.
Virtual regs can be of either class, so that info is attached.
\begin{code}
data Reg
= FixedReg FAST_INT -- A pre-allocated machine register
| MappedReg FAST_INT -- A dynamically allocated machine register
data RegClass
= RcInteger
| RcFloating
deriving Eq
data Reg
= RealReg Int
| VirtualRegI Unique
| VirtualRegF Unique
| MemoryReg Int PrimRep -- A machine "register" actually held in
-- a memory allocated table of
-- registers which didn't fit in real
-- registers.
mkVReg :: Unique -> PrimRep -> Reg
mkVReg u pk
= if isFloatingRep pk then VirtualRegF u else VirtualRegI u
| UnmappedReg Unique PrimRep -- One of an infinite supply of registers,
-- always mapped to one of the earlier
-- two (?) before we're done.
mkReg :: Unique -> PrimRep -> Reg
mkReg = UnmappedReg
isVirtualReg (RealReg _) = False
isVirtualReg (VirtualRegI _) = True
isVirtualReg (VirtualRegF _) = True
isRealReg = not . isVirtualReg
getNewRegNCG :: PrimRep -> NatM Reg
getNewRegNCG pk
= getUniqueNat `thenNat` \ u ->
returnNat (UnmappedReg u pk)
instance Show Reg where
showsPrec _ (FixedReg i) = showString "%" . shows IBOX(i)
showsPrec _ (MappedReg i) = showString "%" . shows IBOX(i)
showsPrec _ (MemoryReg i _) = showString "%M" . shows i
showsPrec _ (UnmappedReg i _) = showString "%U" . shows i
#ifdef DEBUG
instance Outputable Reg where
ppr r = text (show r)
#endif
cmpReg (FixedReg i) (FixedReg i') = cmp_ihash i i'
cmpReg (MappedReg i) (MappedReg i') = cmp_ihash i i'
cmpReg (MemoryReg i _) (MemoryReg i' _) = i `compare` i'
cmpReg (UnmappedReg u _) (UnmappedReg u' _) = compare u u'
cmpReg r1 r2
= let tag1 = tagReg r1
tag2 = tagReg r2
in
if tag1 _LT_ tag2 then LT else GT
where
tagReg (FixedReg _) = (ILIT(1) :: FAST_INT)
tagReg (MappedReg _) = ILIT(2)
tagReg (MemoryReg _ _) = ILIT(3)
tagReg (UnmappedReg _ _) = ILIT(4)
cmp_ihash :: FAST_INT -> FAST_INT -> Ordering
cmp_ihash a1 a2 = if a1 _EQ_ a2 then EQ else if a1 _LT_ a2 then LT else GT
= if isFloatingRep pk
then getUniqueNat `thenNat` \ u -> returnNat (VirtualRegF u)
else getUniqueNat `thenNat` \ u -> returnNat (VirtualRegI u)
instance Eq Reg where
a == b = case (a `compare` b) of { EQ -> True; _ -> False }
a /= b = case (a `compare` b) of { EQ -> False; _ -> True }
(==) (RealReg i1) (RealReg i2) = i1 == i2
(==) (VirtualRegI u1) (VirtualRegI u2) = u1 == u2
(==) (VirtualRegF u1) (VirtualRegF u2) = u1 == u2
(==) reg1 reg2 = False
instance Ord Reg where
a <= b = case (a `compare` b) of { LT -> True; EQ -> True; GT -> False }
a < b = case (a `compare` b) of { LT -> True; EQ -> False; GT -> False }
a >= b = case (a `compare` b) of { LT -> False; EQ -> True; GT -> True }
a > b = case (a `compare` b) of { LT -> False; EQ -> False; GT -> True }
compare a b = cmpReg a b
instance Uniquable Reg where
getUnique (UnmappedReg u _) = u
getUnique (FixedReg i) = mkPseudoUnique1 IBOX(i)
getUnique (MappedReg i) = mkPseudoUnique2 IBOX(i)
getUnique (MemoryReg i _) = mkPseudoUnique3 i
\end{code}
\begin{code}
type RegNo = Int
compare (RealReg i1) (RealReg i2) = compare i1 i2
compare (RealReg _) (VirtualRegI _) = LT
compare (RealReg _) (VirtualRegF _) = LT
compare (VirtualRegI _) (RealReg _) = GT
compare (VirtualRegI u1) (VirtualRegI u2) = compare u1 u2
compare (VirtualRegI _) (VirtualRegF _) = LT
compare (VirtualRegF _) (RealReg _) = GT
compare (VirtualRegF _) (VirtualRegI _) = GT
compare (VirtualRegF u1) (VirtualRegF u2) = compare u1 u2
realReg :: RegNo -> Reg
realReg n@IBOX(i)
= if _IS_TRUE_(freeReg i) then MappedReg i else FixedReg i
extractMappedRegNos :: [Reg] -> [RegNo]
instance Show Reg where
showsPrec _ (RealReg i) = showString (showReg i)
showsPrec _ (VirtualRegI u) = showString "%vI_" . shows u
showsPrec _ (VirtualRegF u) = showString "%vF_" . shows u
extractMappedRegNos regs
= foldr ex [] regs
where
ex (MappedReg i) acc = IBOX(i) : acc -- we'll take it
ex _ acc = acc -- leave it out
instance Outputable Reg where
ppr r = text (show r)
mappedRegNo :: Reg -> RegNo
mappedRegNo (MappedReg i) = IBOX(i)
mappedRegNo _ = pprPanic "mappedRegNo" empty
instance Uniquable Reg where
getUnique (RealReg i) = mkPseudoUnique2 i
getUnique (VirtualRegI u) = u
getUnique (VirtualRegF u) = u
\end{code}
** Machine-specific Reg stuff: **
......@@ -385,25 +355,35 @@ Intel x86 architecture:
\begin{code}
#if i386_TARGET_ARCH
gReg,fReg :: Int -> Int
gReg x = x
fReg x = (8 + x)
fake0, fake1, fake2, fake3, fake4, fake5, eax, ebx, ecx, edx, esp :: Reg
eax = realReg (gReg 0)
ebx = realReg (gReg 1)
ecx = realReg (gReg 2)
edx = realReg (gReg 3)
esi = realReg (gReg 4)
edi = realReg (gReg 5)
ebp = realReg (gReg 6)
esp = realReg (gReg 7)
fake0 = realReg (fReg 0)
fake1 = realReg (fReg 1)
fake2 = realReg (fReg 2)
fake3 = realReg (fReg 3)
fake4 = realReg (fReg 4)
fake5 = realReg (fReg 5)
fake0, fake1, fake2, fake3, fake4, fake5,
eax, ebx, ecx, edx, esp, ebp, esi, edi :: Reg
eax = RealReg 0
ebx = RealReg 1
ecx = RealReg 2
edx = RealReg 3
esi = RealReg 4
edi = RealReg 5
ebp = RealReg 6
esp = RealReg 7
fake0 = RealReg 8
fake1 = RealReg 9
fake2 = RealReg 10
fake3 = RealReg 11
fake4 = RealReg 12
fake5 = RealReg 13
regClass (RealReg i) = if i < 8 then RcInteger else RcFloating
regClass (VirtualRegI u) = RcInteger
regClass (VirtualRegF u) = RcFloating
regNames
= ["%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "%ebp", "%esp",
"%fake0", "%fake1", "%fake2", "%fake3", "%fake4", "%fake5", "%fake6"]
showReg n
= if n >= 0 && n < 14
then regNames !! n
else "%unknown_x86_real_reg_" ++ show n
#endif
\end{code}
......@@ -675,95 +655,110 @@ callerSaves _ = False
magicIdRegMaybe :: MagicId -> Maybe Reg
#ifdef REG_Base
magicIdRegMaybe BaseReg = Just (FixedReg ILIT(REG_Base))
magicIdRegMaybe BaseReg = Just (RealReg REG_Base)
#endif
#ifdef REG_R1
magicIdRegMaybe (VanillaReg _ ILIT(1)) = Just (FixedReg ILIT(REG_R1))
magicIdRegMaybe (VanillaReg _ ILIT(1)) = Just (RealReg REG_R1)
#endif
#ifdef REG_R2
magicIdRegMaybe (VanillaReg _ ILIT(2)) = Just (FixedReg ILIT(REG_R2))
magicIdRegMaybe (VanillaReg _ ILIT(2)) = Just (RealReg REG_R2)
#endif
#ifdef REG_R3
magicIdRegMaybe (VanillaReg _ ILIT(3)) = Just (FixedReg ILIT(REG_R3))
magicIdRegMaybe (VanillaReg _ ILIT(3)) = Just (RealReg REG_R3)
#endif
#ifdef REG_R4
magicIdRegMaybe (VanillaReg _ ILIT(4)) = Just (FixedReg ILIT(REG_R4))
magicIdRegMaybe (VanillaReg _ ILIT(4)) = Just (RealReg REG_R4)
#endif
#ifdef REG_R5
magicIdRegMaybe (VanillaReg _ ILIT(5)) = Just (FixedReg ILIT(REG_R5))
magicIdRegMaybe (VanillaReg _ ILIT(5)) = Just (RealReg REG_R5)
#endif
#ifdef REG_R6
magicIdRegMaybe (VanillaReg _ ILIT(6)) = Just (FixedReg ILIT(REG_R6))
magicIdRegMaybe (VanillaReg _ ILIT(6)) = Just (RealReg REG_R6)
#endif
#ifdef REG_R7
magicIdRegMaybe (VanillaReg _ ILIT(7)) = Just (FixedReg ILIT(REG_R7))
magicIdRegMaybe (VanillaReg _ ILIT(7)) = Just (RealReg REG_R7)
#endif
#ifdef REG_R8
magicIdRegMaybe (VanillaReg _ ILIT(8)) = Just (FixedReg ILIT(REG_R8))
magicIdRegMaybe (VanillaReg _ ILIT(8)) = Just (RealReg REG_R8)
#endif
#ifdef REG_R9
magicIdRegMaybe (VanillaReg _ ILIT(9)) = Just (FixedReg ILIT(REG_R9))
magicIdRegMaybe (VanillaReg _ ILIT(9)) = Just (RealReg REG_R9)
#endif
#ifdef REG_R10
magicIdRegMaybe (VanillaReg _ ILIT(10)) = Just (FixedReg ILIT(REG_R10))
magicIdRegMaybe (VanillaReg _ ILIT(10)) = Just (RealReg REG_R10)
#endif
#ifdef REG_F1
magicIdRegMaybe (FloatReg ILIT(1)) = Just (FixedReg ILIT(REG_F1))
magicIdRegMaybe (FloatReg ILIT(1)) = Just (RealReg REG_F1)
#endif
#ifdef REG_F2
magicIdRegMaybe (FloatReg ILIT(2)) = Just (FixedReg ILIT(REG_F2))
magicIdRegMaybe (FloatReg ILIT(2)) = Just (RealReg REG_F2)
#endif
#ifdef REG_F3
magicIdRegMaybe (FloatReg ILIT(3)) = Just (FixedReg ILIT(REG_F3))
magicIdRegMaybe (FloatReg ILIT(3)) = Just (RealReg REG_F3)
#endif
#ifdef REG_F4
magicIdRegMaybe (FloatReg ILIT(4)) = Just (FixedReg ILIT(REG_F4))
magicIdRegMaybe (FloatReg ILIT(4)) = Just (RealReg REG_F4)
#endif
#ifdef REG_D1
magicIdRegMaybe (DoubleReg ILIT(1)) = Just (FixedReg ILIT(REG_D1))
magicIdRegMaybe (DoubleReg ILIT(1)) = Just (RealReg REG_D1)
#endif
#ifdef REG_D2
magicIdRegMaybe (DoubleReg ILIT(2)) = Just (FixedReg ILIT(REG_D2))
magicIdRegMaybe (DoubleReg ILIT(2)) = Just (RealReg REG_D2)
#endif
#ifdef REG_Sp
magicIdRegMaybe Sp = Just (FixedReg ILIT(REG_Sp))
magicIdRegMaybe Sp = Just (RealReg REG_Sp)
#endif
#ifdef REG_Lng1
magicIdRegMaybe (LongReg _ ILIT(1)) = Just (FixedReg ILIT(REG_Lng1))
magicIdRegMaybe (LongReg _ ILIT(1)) = Just (RealReg REG_Lng1)
#endif
#ifdef REG_Lng2
magicIdRegMaybe (LongReg _ ILIT(2)) = Just (FixedReg ILIT(REG_Lng2))
magicIdRegMaybe (LongReg _ ILIT(2)) = Just (RealReg REG_Lng2)
#endif
#ifdef REG_Su
magicIdRegMaybe Su = Just (FixedReg ILIT(REG_Su))
magicIdRegMaybe Su = Just (RealReg REG_Su)
#endif
#ifdef REG_SpLim
magicIdRegMaybe SpLim = Just (FixedReg ILIT(REG_SpLim))
magicIdRegMaybe SpLim = Just (RealReg REG_SpLim)
#endif
#ifdef REG_Hp
magicIdRegMaybe Hp = Just (FixedReg ILIT(REG_Hp))
magicIdRegMaybe Hp = Just (RealReg REG_Hp)
#endif
#ifdef REG_HpLim
magicIdRegMaybe HpLim = Just (FixedReg ILIT(REG_HpLim))
magicIdRegMaybe HpLim = Just (RealReg REG_HpLim)
#endif
#ifdef REG_CurrentTSO
magicIdRegMaybe CurrentTSO = Just (FixedReg ILIT(REG_CurrentTSO))
magicIdRegMaybe CurrentTSO = Just (RealReg REG_CurrentTSO)
#endif
#ifdef REG_CurrentNursery
magicIdRegMaybe CurrentNursery = Just (FixedReg ILIT(REG_CurrentNursery))
magicIdRegMaybe CurrentNursery = Just (RealReg REG_CurrentNursery)