packages feed

linearscan-hoopl 0.11.1 → 1.0.0

raw patch · 3 files changed

+125/−28 lines, 3 filesdep ~linearscanPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: linearscan

API changes (from Hackage documentation)

- LinearScan.Hoopl: NodeCO :: n C O -> NodeV n
- LinearScan.Hoopl: NodeOC :: n O C -> NodeV n
- LinearScan.Hoopl: NodeOO :: n O O -> NodeV n
- LinearScan.Hoopl: [getNodeCO] :: NodeV n -> n C O
- LinearScan.Hoopl: [getNodeOC] :: NodeV n -> n O C
- LinearScan.Hoopl: [getNodeOO] :: NodeV n -> n O O
- LinearScan.Hoopl: blockInfo :: (NodeAlloc nv nr, NonLocal nv, NonLocal nr) => BlockInfo Env (Block nv C C) (Block nr C C) (NodeV nv) (NodeV nr)
- LinearScan.Hoopl: data NodeV n
- LinearScan.Hoopl: opInfo :: NodeAlloc nv nr => OpInfo Env (NodeV nv) (NodeV nr)
- LinearScan.Hoopl.DSL: SpillStack :: Int -> Int -> Map (Maybe Int) Int -> SpillStack
+ LinearScan.Hoopl.DSL: SpillStack :: Int -> Int -> Map (Maybe VarId) Int -> SpillStack
- LinearScan.Hoopl.DSL: [stackSlots] :: SpillStack -> Map (Maybe Int) Int
+ LinearScan.Hoopl.DSL: [stackSlots] :: SpillStack -> Map (Maybe VarId) Int

Files

LinearScan/Hoopl.hs view
@@ -5,7 +5,10 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} -module LinearScan.Hoopl where+module LinearScan.Hoopl+    ( NodeAlloc(..)+    , allocateHoopl+    ) where  import           Compiler.Hoopl as Hoopl hiding ((<*>)) import           Control.Applicative@@ -24,21 +27,45 @@  class HooplNode nv => NodeAlloc nv nr | nv -> nr, nr -> nv where     isCall   :: nv O O -> Bool+    -- ^ Return @True@ if the operation node represents a call to another+    -- procedure.+     isBranch :: nv O C -> Bool+    -- ^ Return @True@ if the operation node is a branch at the end of a basic+    -- block. Often, the only other possibility is a return instruction.      retargetBranch :: nv O C -> Label -> Label -> nv O C+    -- ^ Given a branching node and a destination label, retarget the branch+    -- so it goes to the second label in place of the first.      mkLabelOp :: Label -> nv C O+    -- ^ Construct a label operation.+     mkJumpOp  :: Label -> nv O C+    -- ^ Construct a jump operation to the given label.      getReferences :: nv e x -> [VarInfo]+    -- ^ Given a node, return its list of 'LinearScan.VarInfo' references.+     setRegisters  :: [((VarId, VarKind), PhysReg)] -> nv e x -> Env (nr e x)+    -- ^ Given a set of register allocations and an operation node, apply+    -- those allocations within the provided 'Env' environment and produce a+    -- result node with the allocations applied.      mkMoveOps    :: PhysReg -> VarId -> PhysReg -> Env [nr O O]+    -- ^ Construct operation(s) to move a variable's value from one register+    -- to another.+     mkSaveOps    :: PhysReg -> VarId -> Env [nr O O]+    -- ^ Construct operation(s) that spill a variable's value from a register+    -- to the spill stack.+     mkRestoreOps :: VarId -> PhysReg -> Env [nr O O]+    -- ^ Construct operation(s) that load a variable's value into a register+    -- from the spill stack.      op1ToString  :: nv e x -> String+    -- ^ Render the given operation node as a 'String'.  data NodeV n = NodeCO { getNodeCO :: n C O }              | NodeOO { getNodeOO :: n O O }@@ -107,14 +134,16 @@            NodeOC n -> op1ToString n     } -allocateHoopl :: (NodeAlloc nv nr, NonLocal nv, NonLocal nr)-              => Int          -- ^ Number of machine registers-              -> Int          -- ^ Offset of the spill stack-              -> Int          -- ^ Size of spilled register in bytes-              -> UseVerifier  -- ^ Whether to use allocation verifier-              -> Label        -- ^ Label of graph entry block-              -> Graph nv C C -- ^ Program graph-              -> (String, Either [String] (Graph nr C C))+allocateHoopl+    :: (NodeAlloc nv nr, NonLocal nv, NonLocal nr)+    => Int          -- ^ Number of machine registers available+    -> Int          -- ^ Offset of the spill stack in bytes+    -> Int          -- ^ Size of a spilled register in bytes+    -> UseVerifier  -- ^ Whether to use the runtime allocation verifier+    -> Label        -- ^ Entry label of the program graph+    -> Graph nv C C -- ^ Hoopl program graph+    -> (String, Either [String] (Graph nr C C))+                   -- ^ Status dump and allocated blocks, or error w/ context allocateHoopl regs offset slotSize useVerifier entry graph =     fmap newGraph <$> runIdentity (go (1 + IM.size (unsafeCoerce body)))   where
LinearScan/Hoopl/DSL.hs view
@@ -3,7 +3,31 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} -module LinearScan.Hoopl.DSL where+module LinearScan.Hoopl.DSL+    ( -- * Compiling Assembly programs+      compile+      -- * Programs+    , ProgramF(..)+    , Program+      -- * Labels+    , Labels+    , getLabel+      -- * Assembly nodes+    , Asm+    , Nodes+    , nodesToList+    , BodyNode+    , bodyNode+    , EndNode+    , endNode+    , LinearScan.Hoopl.DSL.label+    , jump+      -- * Spill stack+    , SpillStack(..)+    , newSpillStack+    , getStackSlot+    , Env+    ) where  import           Compiler.Hoopl as Hoopl hiding ((<*>)) import           Control.Applicative@@ -24,13 +48,24 @@  data SpillStack = SpillStack     { stackPtr      :: Int+      -- ^ Offset to the beginning of the spill stack. This can have whatever+      -- meaning the user of this library desires; it is not used directly by+      -- the allocation code.+     , stackSlotSize :: Int-    , stackSlots    :: M.Map (Maybe Int) Int+      -- ^ The size of a stack slot in bytes. This should be the same or+      -- larger than the size of a register.++    , stackSlots    :: M.Map (Maybe VarId) Int+      -- ^ A mapping of variables to their stack slot offsets. The special+      -- variable 'Nothing' is used for temporary storage, for example when+      -- swapping registers through the stack.     }     deriving (Eq, Show)  type Env = State ([Int], SpillStack) +-- | Create a new 'SpillStack', given an offset and slot size. newSpillStack :: Int -> Int -> SpillStack newSpillStack offset slotSize = SpillStack     { stackPtr      = offset@@ -38,6 +73,8 @@     , stackSlots    = mempty     } +-- | Given a variable identifier, determine its spill stack offset. The value+-- 'Nothing' refers to the temporary stack slot. getStackSlot :: Maybe VarId -> Env Int getStackSlot vid = do     (supply, stack) <- get@@ -51,8 +88,11 @@                 })             return off --- | The 'Asm' monad lets us create labels by name and refer to them later.+-- | Labels is the type of a mapping from label names to Hoopl labels. type Labels = M.Map String Label++-- | The 'Asm' static monad allows for the creation labels by name, and+-- referencing them later. type Asm = StateT Labels SimpleUniqueMonad  getLabel :: String -> Asm Label@@ -66,44 +106,64 @@             return lbl  -- | A series of 'Nodes' is a set of assembly instructions that ends with some---   kind of closing operation, such as a jump, branch or return.+-- kind of closing operation, such as a jump, branch or return. The Free monad+-- is used as a convenient way to describe a list that must result in a+-- closing operation at the end. type Nodes n a = Free ((,) (n O O)) a --- | The 'Nodes' free monad is really just a convenient way to describe a list---   that must result in a closing operation at the end.+-- | 'nodesToList' renders a set of nodes as a list of operations followed by+-- a final value 'a'. nodesToList :: Nodes n a -> (a, [n O O]) nodesToList (Pure a) = (a, []) nodesToList (Free (n, xs)) = (n :) <$> nodesToList xs +-- | A 'BodyNode' represents an instruction within a program. type BodyNode n = Nodes n () +-- | Construct a 'BodyNode' from a Hoopl graph node. bodyNode :: n O O -> BodyNode n bodyNode n = Free (n, Pure ()) +-- | An 'EndNode' represents a program with a final instruction. This+-- instruction is generated from an 'Asm' environment, so that it may refer to+-- and create labels for other blocks. type EndNode n = Nodes n (Asm (n O C)) +-- | Construct an 'EndNode' from a Hoopl final node generated from an 'Asm'+-- environment. endNode :: Asm (n O C) -> EndNode n endNode = return --- | A program is a series of 'Nodes', each associated with a label.+-- | A 'ProgramF' abstracts a generic basic block: a series of 'Nodes',+-- associated with a label, that ends in a final node. data ProgramF n = FreeBlock     { labelEntry :: Label     , labelBody  :: EndNode n     }++-- | A 'Program' abstracts a sequence of basic blocks generated from an 'Asm'+-- environment. type Program n = FreeT ((,) (ProgramF n)) Asm () +-- | Create and associate a label with an series of instructions, creating a+-- 'Program' for that block. label :: String -> EndNode n -> Program n label str body = do     lbl <- lift $ getLabel str     liftF (FreeBlock lbl body, ()) +-- | Create a final jump instruction to the given label. jump :: HooplNode n => String -> EndNode n jump dest = endNode $ mkBranchNode <$> getLabel dest --- | When we compile a program, the result is a closed Hoopl Graph and the---   label corresponding to the requested entry label name.+-- | When a program is compiled, the result is a closed Hoopl Graph, and the+-- label corresponding to the requested entry label name. This is done within+-- a 'SimpleUniqueMonad' so that unique labels may be created. compile :: (NonLocal n, HooplNode n)-        => String -> Program n -> SimpleUniqueMonad (Graph n C C, Label)+        => String    -- ^ Entry label name+        -> Program n -- ^ The assembly language program+        -> SimpleUniqueMonad (Graph n C C, Label)+                    -- ^ Returns the Hoopl 'Graph' and its entry 'Label' compile name prog     = flip evalStateT (mempty :: Labels)     $ do body  <- go prog
linearscan-hoopl.cabal view
@@ -1,5 +1,5 @@ name:          linearscan-hoopl-version:       0.11.1+version:       1.0.0 synopsis:      Makes it easy to use the linearscan register allocator with Hoopl homepage:      http://github.com/jwiegley/linearscan-hoopl license:       BSD3@@ -11,13 +11,21 @@ cabal-version: >=1.10  description:-  This module provides a convenience wrapper and a type class, 'NodeAlloc',-  which makes it much easier to use the @linearscan@ library to allocate-  registers for Hoople intermediate representations.+  This module provides two convenience features for Hoopl users that wish to+  use @linearscan@ for register allocation in their compilers.   .-  Additionally, it provides a DSL for construction of assembly language DSLs-  that compile into Hoople program graphs.  See the tests for a concrete-  example.+  First, it defines a type class called 'NodeAlloc'. After defining an+  instance of this class for your particular graph node type, simply call+  'LinearScan.Hoopl.allocateHoopl'. This is a simpler interface than using+  @linearscan@ directly, which requires two records of functions that are more+  general in nature than the methods of 'NodeAlloc'.+  .+  Second, it provides a DSL for constructing assembly language DSLs that+  compile into Hoople program graphs. See the tests for a concrete example.+  This is mainly useful for constructing tests of intermediate representations.+  .+  Please see the tests for an example of the simple assembly language that is+  used to test the @linearscan@ allocator.  Source-repository head   type:     git@@ -31,7 +39,7 @@   build-depends:           base       >=4.7 && <5     , hoopl      >= 3.10.0.1-    , linearscan >= 0.11 && < 0.12+    , linearscan >= 1.0 && < 1.1     , containers     , transformers     , free@@ -56,7 +64,7 @@     , hspec              >= 1.4.4     , hspec-expectations >= 0.3     , hoopl              >= 3.10.0.1 && < 3.11-    , linearscan         >= 0.11 && < 0.12+    , linearscan         >= 1.0 && < 1.1     , linearscan-hoopl     , containers         >= 0.5.5     , transformers       >= 0.3.0.0