+{-# OPTIONS -fno-warn-missing-signatures #-}
-----------------------------------------------------------------------------
--
-- The register allocator
import MachInstrs
import RegAllocInfo
import RegLiveness
-import Cmm
+import Cmm hiding (RegSet)
import Digraph
import Unique ( Uniquable(getUnique), Unique )
import UniqFM
import UniqSupply
import Outputable
+import State
-#ifndef DEBUG
-import Data.Maybe ( fromJust )
-#endif
-import Data.List ( nub, partition, mapAccumL, foldl')
-import Control.Monad ( when )
+import Data.Maybe
+import Data.List
+import Control.Monad
import Data.Word
import Data.Bits
getFreeRegs cls (FreeRegs g f)
| RcDouble <- cls = go f (0x80000000) 63
| RcInteger <- cls = go g (0x80000000) 31
+ | otherwise = pprPanic "RegAllocLinear.getFreeRegs: Bad cls" (ppr cls)
where
- go x 0 i = []
+ go _ 0 _ = []
go x m i | x .&. m /= 0 = i : (go x (m `shiftR` 1) $! i-1)
| otherwise = go x (m `shiftR` 1) $! i-1
getFreeRegs :: RegClass -> FreeRegs -> [RegNo] -- lazilly
getFreeRegs cls f = go f 0
- where go 0 m = []
+ where go 0 _ = []
go n m
| n .&. 1 /= 0 && regClass (RealReg m) == cls
= m : (go (n `shiftR` 1) $! (m+1))
emptyStackMap = StackMap [0..maxSpillSlots] emptyUFM
getStackSlotFor :: StackMap -> Unique -> (StackMap,Int)
-getStackSlotFor fs@(StackMap [] reserved) reg
- = panic "RegAllocLinear.getStackSlotFor: out of stack slots"
+getStackSlotFor (StackMap [] _) _
+ = panic "RegAllocLinear.getStackSlotFor: out of stack slots, try -fregs-graph"
+ -- This happens with darcs' SHA1.hs, see #1993
+
getStackSlotFor fs@(StackMap (freeSlot:stack') reserved) reg =
case lookupUFM reserved reg of
Just slot -> (fs,slot)
:: LiveCmmTop
-> UniqSM (NatCmmTop, Maybe RegAllocStats)
-regAlloc cmm@(CmmData sec d)
+regAlloc (CmmData sec d)
= return
( CmmData sec d
, Nothing )
-regAlloc cmm@(CmmProc (LiveInfo info _ _) lbl params [])
+regAlloc (CmmProc (LiveInfo info _ _) lbl params (ListGraph []))
= return
- ( CmmProc info lbl params []
+ ( CmmProc info lbl params (ListGraph [])
, Nothing )
-regAlloc cmm@(CmmProc static lbl params comps)
+regAlloc (CmmProc static lbl params (ListGraph comps))
| LiveInfo info (Just first_id) block_live <- static
= do
-- do register allocation on each component.
(final_blocks, stats)
<- linearRegAlloc block_live
$ map (\b -> case b of
- BasicBlock i [b] -> AcyclicSCC b
- BasicBlock i bs -> CyclicSCC bs)
+ BasicBlock _ [b] -> AcyclicSCC b
+ BasicBlock _ bs -> CyclicSCC bs)
$ comps
-- make sure the block that was first in the input list
let ((first':_), rest')
= partition ((== first_id) . blockId) final_blocks
- return ( CmmProc info lbl params (first' : rest')
+ return ( CmmProc info lbl params (ListGraph (first' : rest'))
, Just stats)
+-- bogus. to make non-exhaustive match warning go away.
+regAlloc (CmmProc _ _ _ _)
+ = panic "RegAllocLinear.regAlloc: no match"
-- -----------------------------------------------------------------------------
instruction might still want to read it.
-}
-#ifdef DEBUG
instance Outputable Loc where
ppr l = text (show l)
-#endif
-- | Do register allocation on some basic blocks.
linearRegAlloc block_live sccs
= do us <- getUs
- let (block_assig', stackMap', stats, blocks) =
+ let (_, _, stats, blocks) =
runR emptyBlockMap initFreeRegs emptyRegMap emptyStackMap us
$ linearRA_SCCs block_live [] sccs
return (blocks, stats)
-linearRA_SCCs block_live blocksAcc []
+linearRA_SCCs _ blocksAcc []
= return $ reverse blocksAcc
linearRA_SCCs block_live blocksAcc (AcyclicSCC block : sccs)
-> [Instr] -> [NatBasicBlock] -> [LiveInstr]
-> RegM ([Instr], [NatBasicBlock])
-linearRA block_live instr_acc fixups []
+linearRA _ instr_acc fixups []
= return (reverse instr_acc, fixups)
linearRA block_live instr_acc fixups (instr:instrs)
[NatBasicBlock] -- extra fixup blocks
)
-raInsn block_live new_instrs (Instr instr@(COMMENT _) Nothing)
+raInsn _ new_instrs (Instr (COMMENT _) Nothing)
= return (new_instrs, [])
-raInsn block_live new_instrs (Instr instr@(DELTA n) Nothing)
+raInsn _ new_instrs (Instr (DELTA n) Nothing)
= do
setDeltaR n
return (new_instrs, [])
-}
return (new_instrs, [])
- other -> genRaInsn block_live new_instrs instr
+ _ -> genRaInsn block_live new_instrs instr
(uniqSetToList $ liveDieRead live)
(uniqSetToList $ liveDieWrite live)
-raInsn block_live new_instrs li
+raInsn _ _ li
= pprPanic "raInsn" (text "no match for:" <> ppr li)
-- (j) free up stack slots for dead spilled regs
-- TODO (can't be bothered right now)
- return (patched_instr : w_spills ++ reverse r_spills
+ -- erase reg->reg moves where the source and destination are the same.
+ -- If the src temp didn't die in this instr but happened to be allocated
+ -- to the same real reg as the destination, then we can erase the move anyway.
+ squashed_instr = case isRegRegMove patched_instr of
+ Just (src, dst)
+ | src == dst -> []
+ _ -> [patched_instr]
+
+ return (squashed_instr ++ w_spills ++ reverse r_spills
++ clobber_saves ++ new_instrs,
fixup_blocks)
}}
free <- getFreeRegsR
loop assig free regs
where
- loop assig free _ | free `seq` False = undefined
+ loop _ free _ | free `seq` False = undefined
loop assig free [] = do setAssigR assig; setFreeRegsR free; return ()
loop assig free (RealReg r : rs) = loop assig (releaseReg r free) rs
loop assig free (r:rs) =
clobber assig ((temp, InBoth reg slot) : rest)
| reg `elem` clobbered
= clobber (addToUFM assig temp (InMem slot)) rest
- clobber assig (entry:rest)
+ clobber assig (_:rest)
= clobber assig rest
-- -----------------------------------------------------------------------------
-> [Reg] -- temps to allocate
-> RegM ([Instr], [RegNo])
-allocateRegsAndSpill reading keep spills alloc []
+allocateRegsAndSpill _ _ spills alloc []
= return (spills,reverse alloc)
allocateRegsAndSpill reading keep spills alloc (r:rs) = do
-- InReg, because the memory value is no longer valid.
-- NB2. This is why we must process written registers here, even if they
-- are also read by the same instruction.
- Just (InBoth my_reg mem) -> do
+ Just (InBoth my_reg _) -> do
when (not reading) (setAssigR (addToUFM assig r (InReg my_reg)))
allocateRegsAndSpill reading keep spills (my_reg:alloc) rs
myHead s [] = panic s
-myHead s (x:xs) = x
+myHead _ (x:_) = x
-- -----------------------------------------------------------------------------
-- Joining a jump instruction to its targets
-> [BlockId]
-> RegM ([NatBasicBlock], Instr)
-joinToTargets block_live new_blocks instr []
+joinToTargets _ new_blocks instr []
= return (new_blocks, instr)
joinToTargets block_live new_blocks instr (dest:dests) = do
(freeregs',adjusted_assig))
joinToTargets block_live new_blocks instr dests
- Just (freeregs,dest_assig)
+ Just (_, dest_assig)
-- the assignments match
| ufmToList dest_assig == ufmToList adjusted_assig
| src == mem = [(vreg, loc, [InReg dst])]
| otherwise = [(vreg, loc, [InReg dst, InMem mem])]
-expandNode vreg loc@(InBoth _ src) (InMem dst)
+expandNode _ (InBoth _ src) (InMem dst)
| src == dst = [] -- guaranteed to be true
-expandNode vreg loc@(InBoth src _) (InReg dst)
+expandNode _ (InBoth src _) (InReg dst)
| src == dst = []
-expandNode vreg loc@(InBoth src _) dst
+expandNode vreg (InBoth src _) dst
= expandNode vreg (InReg src) dst
expandNode vreg src dst
-- can join together allocations for different basic blocks.
--
makeMove :: Int -> Unique -> Loc -> Loc -> RegM Instr
-makeMove delta vreg (InReg src) (InReg dst)
+makeMove _ vreg (InReg src) (InReg dst)
= do recordSpill (SpillJoinRR vreg)
return $ mkRegRegMoveInstr (RealReg src) (RealReg dst)
= do recordSpill (SpillJoinRM vreg)
return $ mkSpillInstr (RealReg src) delta dst
-makeMove delta vreg src dst
+makeMove _ vreg src dst
= panic $ "makeMove " ++ show vreg ++ " (" ++ show src ++ ") ("
++ show dst ++ ")"
++ " (workaround: use -fviaC)"
-- we have eliminated any possibility of single-node cylces
-- in expandNode above.
handleComponent :: Int -> Instr -> SCC (Unique, Loc, [Loc]) -> RegM [Instr]
-handleComponent delta instr (AcyclicSCC (vreg,src,dsts))
+handleComponent delta _ (AcyclicSCC (vreg,src,dsts))
= mapM (makeMove delta vreg src) dsts
-- we can not have cycles that involve memory
-- because memory locations (stack slots) are
-- allocated exclusively for a virtual register and
-- therefore can not require a fixup
-handleComponent delta instr (CyclicSCC ((vreg,src@(InReg sreg),dsts):rest))
+handleComponent delta instr (CyclicSCC ((vreg, (InReg sreg),dsts):rest))
= do
spill_id <- getUniqueR
- (saveInstr,slot) <- spillR (RealReg sreg) spill_id
+ (_, slot) <- spillR (RealReg sreg) spill_id
remainingFixUps <- mapM (handleComponent delta instr) (stronglyConnCompR rest)
restoreAndFixInstr <- getRestoreMoves dsts slot
return ([instr] ++ concat remainingFixUps ++ restoreAndFixInstr)
getRestoreMoves _ _ = panic "getRestoreMoves unknown case"
-handleComponent delta instr (CyclicSCC _)
+handleComponent _ _ (CyclicSCC _)
= panic "Register Allocator: handleComponent cyclic"
case unReg thing (RA_State{ ra_blockassig=block_assig, ra_freeregs=freeregs,
ra_assig=assig, ra_delta=0{-???-}, ra_stack=stack,
ra_us = us, ra_spills = [] }) of
- (# state'@RA_State{ ra_blockassig=block_assig, ra_stack=stack', ra_spills=spills' }, returned_thing #)
+ (# state'@RA_State{ ra_blockassig=block_assig, ra_stack=stack' }, returned_thing #)
-> (block_assig, stack', makeRAStats state', returned_thing)
spillR :: Reg -> Unique -> RegM (Instr, Int)
SpillJoinRM r -> (r, [0, 0, 0, 0, 1])) reasons)
+-- | Count reg-reg moves remaining in this code.
+countRegRegMovesNat :: NatCmmTop -> Int
+countRegRegMovesNat cmm
+ = execState (mapGenBlockTopM countBlock cmm) 0
+ where
+ countBlock b@(BasicBlock _ instrs)
+ = do mapM_ countInstr instrs
+ return b
+
+ countInstr instr
+ | Just _ <- isRegRegMove instr
+ = do modify (+ 1)
+ return instr
+
+ | otherwise
+ = return instr
+
+
-- | Pretty print some RegAllocStats
-pprStats :: [RegAllocStats] -> SDoc
-pprStats statss
- = let spills = foldl' (plusUFM_C (zipWith (+)))
+pprStats :: [NatCmmTop] -> [RegAllocStats] -> SDoc
+pprStats code statss
+ = let -- sum up all the instrs inserted by the spiller
+ spills = foldl' (plusUFM_C (zipWith (+)))
emptyUFM
$ map ra_spillInstrs statss
[0, 0, 0, 0, 0]
$ eltsUFM spills
+ -- count how many reg-reg-moves remain in the code
+ moves = sum $ map countRegRegMovesNat code
+
pprSpill (reg, spills)
= parens $ (hcat $ punctuate (text ", ") (doubleQuotes (ppr reg) : map ppr spills))
in ( text "-- spills-added-total"
- $$ text "-- (allocs, clobbers, loads, joinRR, joinRM)"
- $$ (parens $ (hcat $ punctuate (text ", ") (map ppr spillTotals)))
+ $$ text "-- (allocs, clobbers, loads, joinRR, joinRM, reg_reg_moves_remaining)"
+ $$ (parens $ (hcat $ punctuate (text ", ") (map ppr spillTotals ++ [ppr moves])))
$$ text ""
$$ text "-- spills-added"
$$ text "-- (reg_name, allocs, clobbers, loads, joinRR, joinRM)"
#ifdef DEBUG
my_fromJust s p Nothing = pprPanic ("fromJust: " ++ s) p
-my_fromJust s p (Just x) = x
+my_fromJust _ _ (Just x) = x
#else
my_fromJust _ _ = fromJust
#endif