+-----------------------------------------------------------------------------
+-- |Top level driver for the CPS pass
+-----------------------------------------------------------------------------
+cmmCPS :: DynFlags -- ^ Dynamic flags: -dcmm-lint -ddump-cps-cmm
+ -> [GenCmm CmmStatic CmmInfo CmmStmt] -- ^ Input C-- with Proceedures
+ -> IO [GenCmm CmmStatic CmmInfo CmmStmt] -- ^ 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
+
+make_stack_check stack_check_block_id info stack_use next_block_id =
+ BasicBlock stack_check_block_id $
+ check_stmts ++ [CmmBranch next_block_id]
+ where
+ check_stmts =
+ case info of
+ -- If we are given a stack check handler,
+ -- then great, well check the stack.
+ CmmInfo (Just gc_block) _ _
+ -> [CmmCondBranch
+ (CmmMachOp (MO_U_Lt $ cmmRegRep spReg)
+ [CmmReg stack_use, CmmReg spLimReg])
+ gc_block]
+ -- If we aren't given a stack check handler,
+ -- then humph! we just won't check the stack for them.
+ CmmInfo Nothing _ _
+ -> []
+
+-----------------------------------------------------------------------------
+-- |CPS a single CmmTop (proceedure)
+-- Only 'CmmProc' are transformed 'CmmData' will be left alone.
+-----------------------------------------------------------------------------
+
+cpsProc :: UniqSupply
+ -> GenCmmTop CmmStatic CmmInfo CmmStmt -- ^Input proceedure
+ -> [GenCmmTop CmmStatic CmmInfo CmmStmt] -- ^Output proceedure and continuations
+
+-- Data blocks don't need to be CPS transformed
+cpsProc uniqSupply proc@(CmmData _ _) = [proc]
+
+-- Empty functions just don't work with the CPS algorithm, but
+-- they don't need the transformation anyway so just output them directly
+cpsProc uniqSupply proc@(CmmProc _ _ _ []) = [proc]
+
+-- CPS transform for those procs that actually need it
+cpsProc uniqSupply (CmmProc info ident params blocks) = cps_procs
+ where
+ -- We need to be generating uniques for several things.
+ -- We could make this function monadic to handle that
+ -- but since there is no other reason to make it monadic,
+ -- we instead will just split them all up right here.
+ (uniqSupply1, uniqSupply2) = splitUniqSupply uniqSupply
+ uniques :: [[Unique]]
+ uniques = map uniqsFromSupply $ listSplitUniqSupply uniqSupply1
+ (stack_check_block_unique:stack_use_unique:info_uniques) :
+ adaptor_uniques :
+ block_uniques = uniques
+ proc_uniques = map (map uniqsFromSupply . listSplitUniqSupply) $ listSplitUniqSupply uniqSupply2
+
+ stack_use = CmmLocal (LocalReg stack_use_unique (cmmRegRep spReg) KindPtr)
+ stack_check_block_id = BlockId stack_check_block_unique
+ stack_check_block = make_stack_check stack_check_block_id info stack_use (blockId $ head blocks)
+
+ forced_blocks = stack_check_block : blocks
+
+ CmmInfo maybe_gc_block_id update_frame _ = info
+
+ -- Break the block at each function call.
+ -- The part after the function call will have to become a continuation.
+ broken_blocks :: ([(BlockId, ContFormat)], [BrokenBlock])
+ broken_blocks =
+ (\x -> (concatMap fst x, concatMap snd x)) $
+ zipWith3 (breakBlock (maybeToList maybe_gc_block_id))
+ block_uniques
+ forced_blocks
+ (FunctionEntry info ident params :
+ repeat ControlEntry)
+
+ f' = selectContinuations (fst broken_blocks)
+ broken_blocks' = map (makeContinuationEntries f') $
+ concat $
+ zipWith (adaptBlockToFormat f')
+ adaptor_uniques
+ (snd broken_blocks)
+
+ -- 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'