-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Linear scan register allocator, formally verified in Coq -- @package linearscan @version 0.2.0.0 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 :: BlockInfo blk o a b -> OpInfo accType o v a b -> VarInfo v -> [blk a] -> accType -> Either String ([blk b], accType) -- | From the point of view of this library, a basic block is nothing more -- than an ordered sequence of operations. data BlockInfo blk o a b BlockInfo :: (blk a -> Int) -> (blk a -> [Int]) -> (blk a -> [o a]) -> (blk a -> [o b] -> blk b) -> BlockInfo blk o a b blockId :: BlockInfo blk o a b -> blk a -> Int blockSuccessors :: BlockInfo blk o a b -> blk a -> [Int] blockOps :: BlockInfo blk o a b -> blk a -> [o a] setBlockOps :: BlockInfo blk o a b -> blk a -> [o b] -> blk b -- | 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 o v a b OpInfo :: (o a -> OpKind) -> (o a -> ([v], [PhysReg])) -> (Int -> PhysReg -> accType -> (o b, accType)) -> (Int -> PhysReg -> accType -> (o b, accType)) -> (o a -> [(Int, PhysReg)] -> o b) -> OpInfo accType o v a b opKind :: OpInfo accType o v a b -> o a -> OpKind opRefs :: OpInfo accType o v a b -> o a -> ([v], [PhysReg]) saveOp :: OpInfo accType o v a b -> Int -> PhysReg -> accType -> (o b, accType) restoreOp :: OpInfo accType o v a b -> Int -> PhysReg -> accType -> (o b, accType) applyAllocs :: OpInfo accType o v a b -> o a -> [(Int, PhysReg)] -> o b data OpKind IsNormal :: OpKind IsCall :: OpKind IsBranch :: OpKind IsLoopBegin :: OpKind IsLoopEnd :: OpKind -- | 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 v VarInfo :: (v -> Int) -> (v -> VarKind) -> (v -> Bool) -> VarInfo v varId :: VarInfo v -> v -> Int varKind :: VarInfo v -> v -> VarKind regRequired :: VarInfo v -> v -> Bool data VarKind Input :: VarKind Temp :: VarKind Output :: VarKind type PhysReg = Int instance Show OpKind instance Eq OpKind instance Show VarKind instance Eq VarKind