/compiler/GHC/StgToCmm/ExtCode.hs

https://github.com/bgamari/ghc · Haskell · 260 lines · 156 code · 62 blank · 42 comment · 2 complexity · 70105d794e1be6fafb228138a794076c MD5 · raw file

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