-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Linear scan register allocator, formally verified in Coq -- @package linearscan @version 0.3.0.1 module LinearScan -- | Transform a list of basic blocks containing variable references, into -- an equivalent list where each reference is associated with a register -- allocation. Artificial save and restore instructions may also be -- inserted into blocks to indicate spilling and reloading of variables. -- -- In order to call this function, the caller must provide records that -- allow viewing and mutating of the original program graph. -- -- If allocation is found to be impossible -- for example if there are -- simply not enough registers -- a Left value is returned, with a -- string describing the error. allocate :: Int -> BlockInfo blk1 blk2 op1 op2 -> OpInfo accType op1 op2 -> [blk1] -> State accType (Either String [blk2]) -- | From the point of view of this library, a basic block is nothing more -- than an ordered sequence of operations. data BlockInfo blk1 blk2 op1 op2 BlockInfo :: (blk1 -> Int) -> (blk1 -> [Int]) -> (blk1 -> ([op1], [op1], [op1])) -> (blk1 -> [op2] -> [op2] -> [op2] -> blk2) -> BlockInfo blk1 blk2 op1 op2 blockId :: BlockInfo blk1 blk2 op1 op2 -> blk1 -> Int blockSuccessors :: BlockInfo blk1 blk2 op1 op2 -> blk1 -> [Int] blockOps :: BlockInfo blk1 blk2 op1 op2 -> blk1 -> ([op1], [op1], [op1]) setBlockOps :: BlockInfo blk1 blk2 op1 op2 -> blk1 -> [op2] -> [op2] -> [op2] -> blk2 -- | Every operation may reference multiple variables and/or specific -- physical registers. If a physical register is referenced, then that -- register is considered unavailable for allocation over the range of -- such references. -- -- Certain operations have special significance as to how basic blocks -- are organized, and the lifetime of allocations. Thus, if an operation -- begins or ends a loop, or represents a method call, it should be -- indicated using the OpKind field. Indication of calls is -- necessary in order to save and restore all registers around a call, -- but indication of loops is optional, as it's merely avoids reloading -- of spilled variables inside loop bodies. data OpInfo accType op1 op2 OpInfo :: (op1 -> OpKind) -> (op1 -> [VarInfo]) -> (PhysReg -> PhysReg -> State accType [op2]) -> (PhysReg -> PhysReg -> State accType [op2]) -> (PhysReg -> Maybe Int -> State accType [op2]) -> (Maybe Int -> PhysReg -> State accType [op2]) -> (op1 -> [(Int, PhysReg)] -> [op2]) -> OpInfo accType op1 op2 opKind :: OpInfo accType op1 op2 -> op1 -> OpKind opRefs :: OpInfo accType op1 op2 -> op1 -> [VarInfo] moveOp :: OpInfo accType op1 op2 -> PhysReg -> PhysReg -> State accType [op2] swapOp :: OpInfo accType op1 op2 -> PhysReg -> PhysReg -> State accType [op2] saveOp :: OpInfo accType op1 op2 -> PhysReg -> Maybe Int -> State accType [op2] restoreOp :: OpInfo accType op1 op2 -> Maybe Int -> PhysReg -> State accType [op2] applyAllocs :: OpInfo accType op1 op2 -> op1 -> [(Int, PhysReg)] -> [op2] data OpKind IsNormal :: OpKind IsCall :: OpKind IsBranch :: OpKind IsLoopBegin :: OpKind IsLoopEnd :: OpKind type VarId = Int -- | Each variable has associated allocation details, and a flag to -- indicate whether it must be loaded into a register at its point of -- use. Variables are also distinguished by their kind, which allows for -- restricting the scope of their lifetime. For example, output variables -- are not needed in a basic block until the first point of use, while -- the lifetime of input variables extends until their final use. data VarInfo VarInfo :: Either PhysReg VarId -> VarKind -> Bool -> VarInfo varId :: VarInfo -> Either PhysReg VarId varKind :: VarInfo -> VarKind regRequired :: VarInfo -> Bool data VarKind Input :: VarKind Temp :: VarKind Output :: VarKind type PhysReg = Int instance Show OpKind instance Eq OpKind instance Eq VarKind