PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/ghc-7.0.4/compiler/cmm/CmmCPS.hs

http://picorec.googlecode.com/
Haskell | 412 lines | 269 code | 58 blank | 85 comment | 5 complexity | a8fa959e8a11aabc826ed5fcb4e0d325 MD5 | raw file
Possible License(s): BSD-3-Clause, BSD-2-Clause
  1. module CmmCPS (
  2. -- | Converts C-- with full proceedures and parameters
  3. -- to a CPS transformed C-- with the stack made manifest.
  4. cmmCPS
  5. ) where
  6. #include "HsVersions.h"
  7. import BlockId
  8. import Cmm
  9. import CmmLint
  10. import PprCmm
  11. import CmmLive
  12. import CmmBrokenBlock
  13. import CmmProcPoint
  14. import CmmCallConv
  15. import CmmCPSGen
  16. import CmmUtils
  17. import ClosureInfo
  18. import CLabel
  19. import SMRep
  20. import Constants
  21. import DynFlags
  22. import ErrUtils
  23. import Maybes
  24. import Outputable
  25. import UniqSupply
  26. import UniqSet
  27. import Unique
  28. import Control.Monad
  29. -----------------------------------------------------------------------------
  30. -- |Top level driver for the CPS pass
  31. -----------------------------------------------------------------------------
  32. cmmCPS :: DynFlags -- ^ Dynamic flags: -dcmm-lint -ddump-cps-cmm
  33. -> [Cmm] -- ^ Input C-- with Proceedures
  34. -> IO [Cmm] -- ^ Output CPS transformed C--
  35. cmmCPS dflags cmm_with_calls
  36. = do { when (dopt Opt_DoCmmLinting dflags) $
  37. do showPass dflags "CmmLint"
  38. case firstJusts $ map cmmLint cmm_with_calls of
  39. Just err -> do printDump err
  40. ghcExit dflags 1
  41. Nothing -> return ()
  42. ; showPass dflags "CPS"
  43. -- TODO: more lint checking
  44. -- check for use of branches to non-existant blocks
  45. -- check for use of Sp, SpLim, R1, R2, etc.
  46. ; uniqSupply <- mkSplitUniqSupply 'p'
  47. ; let supplies = listSplitUniqSupply uniqSupply
  48. ; let cpsd_cmm = zipWith doCpsProc supplies cmm_with_calls
  49. ; dumpIfSet_dyn dflags Opt_D_dump_cps_cmm "CPS Cmm" (pprCmms cpsd_cmm)
  50. -- TODO: add option to dump Cmm to file
  51. ; return cpsd_cmm }
  52. -----------------------------------------------------------------------------
  53. -- |CPS a single CmmTop (proceedure)
  54. -- Only 'CmmProc' are transformed 'CmmData' will be left alone.
  55. -----------------------------------------------------------------------------
  56. doCpsProc :: UniqSupply -> Cmm -> Cmm
  57. doCpsProc s (Cmm c)
  58. = Cmm $ concat $ zipWith cpsProc (listSplitUniqSupply s) c
  59. cpsProc :: UniqSupply
  60. -> CmmTop -- ^Input procedure
  61. -> [CmmTop] -- ^Output procedures;
  62. -- a single input procedure is converted to
  63. -- multiple output procedures
  64. -- Data blocks don't need to be CPS transformed
  65. cpsProc _ proc@(CmmData _ _) = [proc]
  66. -- Empty functions just don't work with the CPS algorithm, but
  67. -- they don't need the transformation anyway so just output them directly
  68. cpsProc _ proc@(CmmProc _ _ _ (ListGraph []))
  69. = pprTrace "cpsProc: unexpected empty proc" (ppr proc) [proc]
  70. -- CPS transform for those procs that actually need it
  71. -- The plan is this:
  72. --
  73. -- * Introduce a stack-check block as the first block
  74. -- * The first blocks gets a FunctionEntry; the rest are ControlEntry
  75. -- * Now break each block into a bunch of blocks (at call sites);
  76. -- all but the first will be ContinuationEntry
  77. --
  78. cpsProc uniqSupply (CmmProc info ident params (ListGraph blocks)) = cps_procs
  79. where
  80. -- We need to be generating uniques for several things.
  81. -- We could make this function monadic to handle that
  82. -- but since there is no other reason to make it monadic,
  83. -- we instead will just split them all up right here.
  84. (uniqSupply1, uniqSupply2) = splitUniqSupply uniqSupply
  85. uniques :: [[Unique]]
  86. uniques = map uniqsFromSupply $ listSplitUniqSupply uniqSupply1
  87. (stack_check_block_unique:stack_use_unique:adaptor_uniques) :
  88. block_uniques = uniques
  89. proc_uniques = map (map (map uniqsFromSupply . listSplitUniqSupply) . listSplitUniqSupply) $ listSplitUniqSupply uniqSupply2
  90. stack_use = CmmLocal (LocalReg stack_use_unique (cmmRegType spReg))
  91. stack_check_block_id = BlockId stack_check_block_unique
  92. stack_check_block = make_stack_check stack_check_block_id info stack_use (blockId $ head blocks)
  93. forced_blocks = stack_check_block : blocks
  94. CmmInfo maybe_gc_block_id update_frame _ = info
  95. -- Break the block at each function call.
  96. -- The part after the function call will have to become a continuation.
  97. broken_blocks :: ([(BlockId, ContFormat)], [BrokenBlock])
  98. broken_blocks =
  99. (\x -> (concatMap fst x, concatMap snd x)) $
  100. zipWith3 (breakBlock (maybeToList maybe_gc_block_id))
  101. block_uniques
  102. forced_blocks
  103. (FunctionEntry info ident params :
  104. repeat ControlEntry)
  105. f' = selectContinuations (fst broken_blocks)
  106. broken_blocks' = map (makeContinuationEntries f') $
  107. concat $
  108. zipWith (adaptBlockToFormat f')
  109. adaptor_uniques
  110. (snd broken_blocks)
  111. -- Calculate live variables for each broken block.
  112. --
  113. -- Nothing can be live on entry to the first block
  114. -- so we could take the tail, but for now we wont
  115. -- to help future proof the code.
  116. live :: BlockEntryLiveness
  117. live = cmmLiveness $ map cmmBlockFromBrokenBlock broken_blocks'
  118. -- Calculate which blocks must be made into full fledged procedures.
  119. proc_points :: UniqSet BlockId
  120. proc_points = calculateProcPoints broken_blocks'
  121. -- Construct a map so we can lookup a broken block by its 'BlockId'.
  122. block_env :: BlockEnv BrokenBlock
  123. block_env = blocksToBlockEnv broken_blocks'
  124. -- Group the blocks into continuations based on the set of proc-points.
  125. continuations :: [Continuation (Either C_SRT CmmInfo)]
  126. continuations = map (gatherBlocksIntoContinuation live proc_points block_env)
  127. (uniqSetToList proc_points)
  128. -- Select the stack format on entry to each continuation.
  129. -- Return the max stack offset and an association list
  130. --
  131. -- This is an association list instead of a UniqFM because
  132. -- CLabel's don't have a 'Uniqueable' instance.
  133. formats :: [(CLabel, -- key
  134. (CmmFormals, -- arguments
  135. Maybe CLabel, -- label in top slot
  136. [Maybe LocalReg]))] -- slots
  137. formats = selectContinuationFormat live continuations
  138. -- Do a little meta-processing on the stack formats such as
  139. -- getting the individual frame sizes and the maximum frame size
  140. formats' :: (WordOff, WordOff, [(CLabel, ContinuationFormat)])
  141. formats'@(_, _, format_list) = processFormats formats update_frame continuations
  142. -- Update the info table data on the continuations with
  143. -- the selected stack formats.
  144. continuations' :: [Continuation CmmInfo]
  145. continuations' = map (applyContinuationFormat format_list) continuations
  146. -- Do the actual CPS transform.
  147. cps_procs :: [CmmTop]
  148. cps_procs = zipWith (continuationToProc formats' stack_use) proc_uniques continuations'
  149. make_stack_check :: BlockId -> CmmInfo -> CmmReg -> BlockId
  150. -> GenBasicBlock CmmStmt
  151. make_stack_check stack_check_block_id info stack_use next_block_id =
  152. BasicBlock stack_check_block_id $
  153. check_stmts ++ [CmmBranch next_block_id]
  154. where
  155. check_stmts =
  156. case info of
  157. -- If we are given a stack check handler,
  158. -- then great, well check the stack.
  159. CmmInfo (Just gc_block) _ _
  160. -> [CmmCondBranch
  161. (CmmMachOp (MO_U_Lt (typeWidth (cmmRegType spReg)))
  162. [CmmReg stack_use, CmmReg spLimReg])
  163. gc_block]
  164. -- If we aren't given a stack check handler,
  165. -- then humph! we just won't check the stack for them.
  166. CmmInfo Nothing _ _
  167. -> []
  168. -----------------------------------------------------------------------------
  169. collectNonProcPointTargets ::
  170. UniqSet BlockId -> BlockEnv BrokenBlock
  171. -> UniqSet BlockId -> [BlockId] -> UniqSet BlockId
  172. collectNonProcPointTargets proc_points blocks current_targets new_blocks =
  173. if sizeUniqSet current_targets == sizeUniqSet new_targets
  174. then current_targets
  175. else foldl
  176. (collectNonProcPointTargets proc_points blocks)
  177. new_targets
  178. (map (:[]) targets)
  179. where
  180. blocks' = map (lookupWithDefaultBEnv blocks (panic "TODO")) new_blocks
  181. targets =
  182. -- Note the subtlety that since the extra branch after a call
  183. -- will always be to a block that is a proc-point,
  184. -- this subtraction will always remove that case
  185. uniqSetToList $ (unionManyUniqSets $ map (mkUniqSet . brokenBlockTargets) blocks')
  186. `minusUniqSet` proc_points
  187. -- TODO: remove redundant uniqSetToList
  188. new_targets = current_targets `unionUniqSets` (mkUniqSet targets)
  189. -- TODO: insert proc point code here
  190. -- * Branches and switches to proc points may cause new blocks to be created
  191. -- (or proc points could leave behind phantom blocks that just jump to them)
  192. -- * Proc points might get some live variables passed as arguments
  193. gatherBlocksIntoContinuation ::
  194. BlockEntryLiveness -> UniqSet BlockId -> BlockEnv BrokenBlock
  195. -> BlockId -> Continuation (Either C_SRT CmmInfo)
  196. gatherBlocksIntoContinuation live proc_points blocks start =
  197. Continuation info_table clabel params is_gc_cont body
  198. where
  199. children = (collectNonProcPointTargets proc_points blocks (unitUniqSet start) [start]) `minusUniqSet` (unitUniqSet start)
  200. start_block = lookupWithDefaultBEnv blocks unknown_block start
  201. children_blocks = map (lookupWithDefaultBEnv blocks unknown_block) (uniqSetToList children)
  202. unknown_block :: a -- Used at more than one type
  203. unknown_block = panic "unknown block in gatherBlocksIntoContinuation"
  204. body = start_block : children_blocks
  205. -- We can't properly annotate the continuation's stack parameters
  206. -- at this point because this is before stack selection
  207. -- but we want to keep the C_SRT around so we use 'Either'.
  208. info_table = case start_block_entry of
  209. FunctionEntry info _ _ -> Right info
  210. ContinuationEntry _ srt _ -> Left srt
  211. ControlEntry -> Right (CmmInfo Nothing Nothing CmmNonInfoTable)
  212. is_gc_cont = case start_block_entry of
  213. FunctionEntry _ _ _ -> False
  214. ContinuationEntry _ _ gc_cont -> gc_cont
  215. ControlEntry -> False
  216. start_block_entry = brokenBlockEntry start_block
  217. clabel = case start_block_entry of
  218. FunctionEntry _ label _ -> label
  219. _ -> mkReturnPtLabel $ getUnique start
  220. params = case start_block_entry of
  221. FunctionEntry _ _ args -> args
  222. ContinuationEntry args _ _ -> args
  223. ControlEntry ->
  224. uniqSetToList $
  225. lookupWithDefaultBEnv live unknown_block start
  226. -- it's a proc-point, pass lives in parameter registers
  227. --------------------------------------------------------------------------------
  228. -- For now just select the continuation orders in the order they are in the set with no gaps
  229. selectContinuationFormat :: BlockEnv CmmLive
  230. -> [Continuation (Either C_SRT CmmInfo)]
  231. -> [(CLabel, (CmmFormals, Maybe CLabel, [Maybe LocalReg]))]
  232. selectContinuationFormat live continuations =
  233. map (\c -> (continuationLabel c, selectContinuationFormat' c)) continuations
  234. where
  235. -- User written continuations
  236. selectContinuationFormat' (Continuation
  237. (Right (CmmInfo _ _ (CmmInfoTable _ _ _ (ContInfo format _))))
  238. label formals _ _) =
  239. (formals, Just label, format)
  240. -- Either user written non-continuation code
  241. -- or CPS generated proc-points
  242. selectContinuationFormat' (Continuation (Right _) _ formals _ _) =
  243. (formals, Nothing, [])
  244. -- CPS generated continuations
  245. selectContinuationFormat' (Continuation (Left _) label formals _ blocks) =
  246. -- TODO: assumes the first block is the entry block
  247. let ident = brokenBlockId $ head blocks -- TODO: CLabel isn't a uniquable, but we need a better way than this
  248. in (formals,
  249. Just label,
  250. map Just $ uniqSetToList $
  251. lookupWithDefaultBEnv live unknown_block ident)
  252. unknown_block = panic "unknown BlockId in selectContinuationFormat"
  253. processFormats :: [(CLabel, (CmmFormals, Maybe CLabel, [Maybe LocalReg]))]
  254. -> Maybe UpdateFrame
  255. -> [Continuation (Either C_SRT CmmInfo)]
  256. -> (WordOff, WordOff, [(CLabel, ContinuationFormat)])
  257. processFormats formats update_frame continuations =
  258. (max_size + update_frame_size, update_frame_size, formats')
  259. where
  260. max_size = maximum $
  261. 0 : map (continuationMaxStack formats') continuations
  262. formats' = map make_format formats
  263. make_format (label, (formals, top, stack)) =
  264. (label,
  265. ContinuationFormat {
  266. continuation_formals = formals,
  267. continuation_label = top,
  268. continuation_frame_size = stack_size stack +
  269. if isJust top
  270. then label_size
  271. else 0,
  272. continuation_stack = stack })
  273. update_frame_size = case update_frame of
  274. Nothing -> 0
  275. (Just (UpdateFrame _ args))
  276. -> label_size + update_size args
  277. update_size [] = 0
  278. update_size (expr:exprs) = width + update_size exprs
  279. where
  280. width = (widthInBytes $ typeWidth $ cmmExprType expr) `quot` wORD_SIZE
  281. -- TODO: it would be better if we had a machRepWordWidth
  282. -- TODO: get rid of "+ 1" etc.
  283. label_size = 1 :: WordOff
  284. stack_size [] = 0
  285. stack_size (Nothing:formats) = 1 + stack_size formats -- one dead word
  286. stack_size (Just reg:formats) = width + stack_size formats
  287. where
  288. width = (widthInBytes $ typeWidth $ localRegType reg) `quot` wORD_SIZE
  289. -- TODO: it would be better if we had a machRepWordWidth
  290. continuationMaxStack :: [(CLabel, ContinuationFormat)]
  291. -> Continuation a
  292. -> WordOff
  293. continuationMaxStack _ (Continuation _ _ _ True _) = 0
  294. continuationMaxStack formats (Continuation _ label _ False blocks) =
  295. max_arg_size + continuation_frame_size stack_format
  296. where
  297. stack_format = maybe unknown_format id $ lookup label formats
  298. unknown_format = panic "Unknown format in continuationMaxStack"
  299. max_arg_size = maximum $ 0 : map block_max_arg_size blocks
  300. block_max_arg_size block =
  301. maximum (final_arg_size (brokenBlockExit block) :
  302. map stmt_arg_size (brokenBlockStmts block))
  303. final_arg_size (FinalReturn args) =
  304. argumentsSize (cmmExprType . hintlessCmm) args
  305. final_arg_size (FinalJump _ args) =
  306. argumentsSize (cmmExprType . hintlessCmm) args
  307. final_arg_size (FinalCall _ _ _ _ _ _ True) = 0
  308. final_arg_size (FinalCall next _ _ args _ _ False) =
  309. -- We have to account for the stack used when we build a frame
  310. -- for the *next* continuation from *this* continuation
  311. argumentsSize (cmmExprType . hintlessCmm) args +
  312. continuation_frame_size next_format
  313. where
  314. next_format = maybe unknown_format id $ lookup next' formats
  315. next' = mkReturnPtLabel $ getUnique next
  316. final_arg_size _ = 0
  317. stmt_arg_size (CmmJump _ args) =
  318. argumentsSize (cmmExprType . hintlessCmm) args
  319. stmt_arg_size (CmmCall _ _ _ (CmmSafe _) _) =
  320. panic "Safe call in processFormats"
  321. stmt_arg_size (CmmReturn _) =
  322. panic "CmmReturn in processFormats"
  323. stmt_arg_size _ = 0
  324. -----------------------------------------------------------------------------
  325. applyContinuationFormat :: [(CLabel, ContinuationFormat)]
  326. -> Continuation (Either C_SRT CmmInfo)
  327. -> Continuation CmmInfo
  328. -- User written continuations
  329. applyContinuationFormat formats
  330. (Continuation (Right (CmmInfo gc update_frame
  331. (CmmInfoTable clos prof tag (ContInfo _ srt))))
  332. label formals is_gc blocks) =
  333. Continuation (CmmInfo gc update_frame (CmmInfoTable clos prof tag (ContInfo format srt)))
  334. label formals is_gc blocks
  335. where
  336. format = continuation_stack $ maybe unknown_block id $ lookup label formats
  337. unknown_block = panic "unknown BlockId in applyContinuationFormat"
  338. -- Either user written non-continuation code or CPS generated proc-point
  339. applyContinuationFormat _ (Continuation
  340. (Right info) label formals is_gc blocks) =
  341. Continuation info label formals is_gc blocks
  342. -- CPS generated continuations
  343. applyContinuationFormat formats (Continuation
  344. (Left srt) label formals is_gc blocks) =
  345. Continuation (CmmInfo gc Nothing (CmmInfoTable undefined prof tag (ContInfo (continuation_stack $ format) srt)))
  346. label formals is_gc blocks
  347. where
  348. gc = Nothing -- Generated continuations never need a stack check
  349. -- TODO prof: this is the same as the current implementation
  350. -- but I think it could be improved
  351. prof = ProfilingInfo zeroCLit zeroCLit
  352. tag = rET_SMALL -- cmmToRawCmm may convert it to rET_BIG
  353. format = maybe unknown_block id $ lookup label formats
  354. unknown_block = panic "unknown BlockId in applyContinuationFormat"