PageRenderTime 27ms CodeModel.GetById 1ms RepoModel.GetById 1ms app.codeStats 0ms

/compiler/codeGen/StgCmmExtCode.hs

http://github.com/ghc/ghc
Haskell | 248 lines | 146 code | 61 blank | 41 comment | 0 complexity | 496a7ea7366e6a872603f809e55ceaad MD5 | raw file
Possible License(s): MIT, BSD-3-Clause, GPL-3.0
  1. -- | Our extended FCode monad.
  2. -- We add a mapping from names to CmmExpr, to support local variable names in
  3. -- the concrete C-- code. The unique supply of the underlying FCode monad
  4. -- is used to grab a new unique for each local variable.
  5. -- In C--, a local variable can be declared anywhere within a proc,
  6. -- and it scopes from the beginning of the proc to the end. Hence, we have
  7. -- to collect declarations as we parse the proc, and feed the environment
  8. -- back in circularly (to avoid a two-pass algorithm).
  9. module StgCmmExtCode (
  10. CmmParse, unEC,
  11. Named(..), Env,
  12. loopDecls,
  13. getEnv,
  14. withName,
  15. getName,
  16. newLocal,
  17. newLabel,
  18. newBlockId,
  19. newFunctionName,
  20. newImport,
  21. lookupLabel,
  22. lookupName,
  23. code,
  24. emit, emitLabel, emitAssign, emitStore,
  25. getCode, getCodeR, getCodeScoped,
  26. emitOutOfLine,
  27. withUpdFrameOff, getUpdFrameOff
  28. )
  29. where
  30. import qualified StgCmmMonad as F
  31. import StgCmmMonad (FCode, newUnique)
  32. import Cmm
  33. import CLabel
  34. import MkGraph
  35. -- import BasicTypes
  36. import BlockId
  37. import DynFlags
  38. import FastString
  39. import Module
  40. import UniqFM
  41. import Unique
  42. import Control.Monad (liftM, ap)
  43. -- | The environment contains variable definitions or blockids.
  44. data Named
  45. = VarN CmmExpr -- ^ Holds CmmLit(CmmLabel ..) which gives the label type,
  46. -- eg, RtsLabel, ForeignLabel, CmmLabel etc.
  47. | FunN UnitId -- ^ A function name from this package
  48. | LabelN BlockId -- ^ A blockid of some code or data.
  49. -- | An environment of named things.
  50. type Env = UniqFM Named
  51. -- | Local declarations that are in scope during code generation.
  52. type Decls = [(FastString,Named)]
  53. -- | Does a computation in the FCode monad, with a current environment
  54. -- and a list of local declarations. Returns the resulting list of declarations.
  55. newtype CmmParse a
  56. = EC { unEC :: String -> Env -> Decls -> FCode (Decls, a) }
  57. type ExtCode = CmmParse ()
  58. returnExtFC :: a -> CmmParse a
  59. returnExtFC a = EC $ \_ _ s -> return (s, a)
  60. thenExtFC :: CmmParse a -> (a -> CmmParse b) -> CmmParse b
  61. thenExtFC (EC m) k = EC $ \c e s -> do (s',r) <- m c e s; unEC (k r) c e s'
  62. instance Functor CmmParse where
  63. fmap = liftM
  64. instance Applicative CmmParse where
  65. pure = returnExtFC
  66. (<*>) = ap
  67. instance Monad CmmParse where
  68. (>>=) = thenExtFC
  69. instance HasDynFlags CmmParse where
  70. getDynFlags = EC (\_ _ d -> do dflags <- getDynFlags
  71. return (d, dflags))
  72. -- | Takes the variable decarations and imports from the monad
  73. -- and makes an environment, which is looped back into the computation.
  74. -- In this way, we can have embedded declarations that scope over the whole
  75. -- procedure, and imports that scope over the entire module.
  76. -- Discards the local declaration contained within decl'
  77. --
  78. loopDecls :: CmmParse a -> CmmParse a
  79. loopDecls (EC fcode) =
  80. EC $ \c e globalDecls -> do
  81. (_, a) <- F.fixC $ \ ~(decls, _) ->
  82. fcode c (addListToUFM e decls) globalDecls
  83. return (globalDecls, a)
  84. -- | Get the current environment from the monad.
  85. getEnv :: CmmParse Env
  86. getEnv = EC $ \_ e s -> return (s, e)
  87. -- | Get the current context name from the monad
  88. getName :: CmmParse String
  89. getName = EC $ \c _ s -> return (s, c)
  90. -- | Set context name for a sub-parse
  91. withName :: String -> CmmParse a -> CmmParse a
  92. withName c' (EC fcode) = EC $ \_ e s -> fcode c' e s
  93. addDecl :: FastString -> Named -> ExtCode
  94. addDecl name named = EC $ \_ _ s -> return ((name, named) : s, ())
  95. -- | Add a new variable to the list of local declarations.
  96. -- The CmmExpr says where the value is stored.
  97. addVarDecl :: FastString -> CmmExpr -> ExtCode
  98. addVarDecl var expr = addDecl var (VarN expr)
  99. -- | Add a new label to the list of local declarations.
  100. addLabel :: FastString -> BlockId -> ExtCode
  101. addLabel name block_id = addDecl name (LabelN block_id)
  102. -- | Create a fresh local variable of a given type.
  103. newLocal
  104. :: CmmType -- ^ data type
  105. -> FastString -- ^ name of variable
  106. -> CmmParse LocalReg -- ^ register holding the value
  107. newLocal ty name = do
  108. u <- code newUnique
  109. let reg = LocalReg u ty
  110. addVarDecl name (CmmReg (CmmLocal reg))
  111. return reg
  112. -- | Allocate a fresh label.
  113. newLabel :: FastString -> CmmParse BlockId
  114. newLabel name = do
  115. u <- code newUnique
  116. addLabel name (mkBlockId u)
  117. return (mkBlockId u)
  118. newBlockId :: CmmParse BlockId
  119. newBlockId = code F.newLabelC
  120. -- | Add add a local function to the environment.
  121. newFunctionName
  122. :: FastString -- ^ name of the function
  123. -> UnitId -- ^ package of the current module
  124. -> ExtCode
  125. newFunctionName name pkg = addDecl name (FunN pkg)
  126. -- | Add an imported foreign label to the list of local declarations.
  127. -- If this is done at the start of the module the declaration will scope
  128. -- over the whole module.
  129. newImport
  130. :: (FastString, CLabel)
  131. -> CmmParse ()
  132. newImport (name, cmmLabel)
  133. = addVarDecl name (CmmLit (CmmLabel cmmLabel))
  134. -- | Lookup the BlockId bound to the label with this name.
  135. -- If one hasn't been bound yet, create a fresh one based on the
  136. -- Unique of the name.
  137. lookupLabel :: FastString -> CmmParse BlockId
  138. lookupLabel name = do
  139. env <- getEnv
  140. return $
  141. case lookupUFM env name of
  142. Just (LabelN l) -> l
  143. _other -> mkBlockId (newTagUnique (getUnique name) 'L')
  144. -- | Lookup the location of a named variable.
  145. -- Unknown names are treated as if they had been 'import'ed from the runtime system.
  146. -- This saves us a lot of bother in the RTS sources, at the expense of
  147. -- deferring some errors to link time.
  148. lookupName :: FastString -> CmmParse CmmExpr
  149. lookupName name = do
  150. env <- getEnv
  151. return $
  152. case lookupUFM env name of
  153. Just (VarN e) -> e
  154. Just (FunN pkg) -> CmmLit (CmmLabel (mkCmmCodeLabel pkg name))
  155. _other -> CmmLit (CmmLabel (mkCmmCodeLabel rtsUnitId name))
  156. -- | Lift an FCode computation into the CmmParse monad
  157. code :: FCode a -> CmmParse a
  158. code fc = EC $ \_ _ s -> do
  159. r <- fc
  160. return (s, r)
  161. emit :: CmmAGraph -> CmmParse ()
  162. emit = code . F.emit
  163. emitLabel :: BlockId -> CmmParse ()
  164. emitLabel = code . F.emitLabel
  165. emitAssign :: CmmReg -> CmmExpr -> CmmParse ()
  166. emitAssign l r = code (F.emitAssign l r)
  167. emitStore :: CmmExpr -> CmmExpr -> CmmParse ()
  168. emitStore l r = code (F.emitStore l r)
  169. getCode :: CmmParse a -> CmmParse CmmAGraph
  170. getCode (EC ec) = EC $ \c e s -> do
  171. ((s',_), gr) <- F.getCodeR (ec c e s)
  172. return (s', gr)
  173. getCodeR :: CmmParse a -> CmmParse (a, CmmAGraph)
  174. getCodeR (EC ec) = EC $ \c e s -> do
  175. ((s', r), gr) <- F.getCodeR (ec c e s)
  176. return (s', (r,gr))
  177. getCodeScoped :: CmmParse a -> CmmParse (a, CmmAGraphScoped)
  178. getCodeScoped (EC ec) = EC $ \c e s -> do
  179. ((s', r), gr) <- F.getCodeScoped (ec c e s)
  180. return (s', (r,gr))
  181. emitOutOfLine :: BlockId -> CmmAGraphScoped -> CmmParse ()
  182. emitOutOfLine l g = code (F.emitOutOfLine l g)
  183. withUpdFrameOff :: UpdFrameOffset -> CmmParse () -> CmmParse ()
  184. withUpdFrameOff size inner
  185. = EC $ \c e s -> F.withUpdFrameOff size $ (unEC inner) c e s
  186. getUpdFrameOff :: CmmParse UpdFrameOffset
  187. getUpdFrameOff = code $ F.getUpdFrameOff