+-----------------------------------------------------------------------------
+-- |Top level driver for the CPS pass
+-----------------------------------------------------------------------------
+cmmCPS :: DynFlags -- ^ Dynamic flags: -dcmm-lint -ddump-cps-cmm
+ -> [Cmm] -- ^ Input C-- with Proceedures
+ -> IO [Cmm] -- ^ Output CPS transformed C--
+cmmCPS dflags abstractC = do
+ when (dopt Opt_DoCmmLinting dflags) $
+ do showPass dflags "CmmLint"
+ case firstJust $ map cmmLint abstractC of
+ Just err -> do printDump err
+ ghcExit dflags 1
+ Nothing -> return ()
+ showPass dflags "CPS"
+
+ -- TODO: more lint checking
+ -- check for use of branches to non-existant blocks
+ -- check for use of Sp, SpLim, R1, R2, etc.
+
+ uniqSupply <- mkSplitUniqSupply 'p'
+ let supplies = listSplitUniqSupply uniqSupply
+ let doCpsProc s (Cmm c) =
+ Cmm $ concat $ zipWith cpsProc (listSplitUniqSupply s) c
+ let continuationC = zipWith doCpsProc supplies abstractC
+
+ dumpIfSet_dyn dflags Opt_D_dump_cps_cmm "CPS Cmm" (pprCmms continuationC)
+
+ -- TODO: add option to dump Cmm to file
+
+ return continuationC
+
+-----------------------------------------------------------------------------
+-- |CPS a single CmmTop (proceedure)
+-- Only 'CmmProc' are transformed 'CmmData' will be left alone.
+-----------------------------------------------------------------------------
+
+cpsProc :: UniqSupply
+ -> CmmTop -- ^Input proceedure
+ -> [CmmTop] -- ^Output proceedure and continuations
+cpsProc uniqSupply x@(CmmData _ _) = [x]
+cpsProc uniqSupply x@(CmmProc info_table ident params blocks) = cps_procs
+ where
+ uniqes :: [[Unique]]
+ uniqes = map uniqsFromSupply $ listSplitUniqSupply uniqSupply
+
+ -- Break the block at each function call.
+ -- The part after the function call will have to become a continuation.
+ broken_blocks :: [BrokenBlock]
+ broken_blocks =
+ concat $ zipWith3 breakBlock uniqes blocks
+ (FunctionEntry ident params:repeat ControlEntry)
+
+ -- Calculate live variables for each broken block.
+ --
+ -- Nothing can be live on entry to the first block
+ -- so we could take the tail, but for now we wont
+ -- to help future proof the code.
+ live :: BlockEntryLiveness
+ live = cmmLiveness $ map cmmBlockFromBrokenBlock broken_blocks
+
+ -- Calculate which blocks must be made into full fledged procedures.
+ proc_points :: UniqSet BlockId
+ proc_points = calculateProcPoints broken_blocks
+
+ -- Construct a map so we can lookup a broken block by its 'BlockId'.
+ block_env :: BlockEnv BrokenBlock
+ block_env = blocksToBlockEnv broken_blocks
+
+ -- Group the blocks into continuations based on the set of proc-points.
+ continuations :: [Continuation]
+ continuations = map (gatherBlocksIntoContinuation proc_points block_env)
+ (uniqSetToList proc_points)
+
+ -- Select the stack format on entry to each continuation.
+ --
+ -- This is an association list instead of a UniqFM because
+ -- CLabel's don't have a 'Uniqueable' instance.
+ formats :: [(CLabel, StackFormat)]
+ formats = selectStackFormat live continuations
+
+ -- Do the actual CPS transform.
+ cps_procs :: [CmmTop]
+ cps_procs = map (continuationToProc formats) continuations
+