X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=blobdiff_plain;f=compiler%2Fcmm%2FCmmCPSGen.hs;h=dcbb0a53ad9257c6e6c84a77ebb331540b34f39c;hp=49ac9ab73ec02c2d73bf7c3c39b4c731063d4b48;hb=0d80489c9b9f2421f65d8dd86c1e50c6bb429715;hpb=1f8efd5d6214c490ef4942134abf5de9f468d29c diff --git a/compiler/cmm/CmmCPSGen.hs b/compiler/cmm/CmmCPSGen.hs index 49ac9ab..dcbb0a5 100644 --- a/compiler/cmm/CmmCPSGen.hs +++ b/compiler/cmm/CmmCPSGen.hs @@ -1,3 +1,10 @@ +{-# OPTIONS -w #-} +-- The above warning supression flag is a temporary kludge. +-- While working on this module you are encouraged to remove it and fix +-- any warnings in the module. See +-- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings +-- for details + module CmmCPSGen ( -- | Converts continuations into full proceedures. -- The main work of the CPS transform that everything else is setting-up. @@ -6,8 +13,7 @@ module CmmCPSGen ( ContinuationFormat(..), ) where -#include "HsVersions.h" - +import BlockId import Cmm import CLabel import CmmBrokenBlock -- Data types only @@ -15,8 +21,9 @@ import MachOp import CmmUtils import CmmCallConv -import CgProf (curCCS, curCCSAddr) -import CgUtils (cmmOffsetW) +import CgProf +import CgUtils +import CgInfoTbls import SMRep import ForeignCall @@ -24,15 +31,11 @@ import Constants import StaticFlags import Unique import Maybe +import List +import FastString import Panic -import MachRegs (callerSaveVolatileRegs) - -- HACK: this is part of the NCG so we shouldn't use this, but we need - -- it for now to eliminate the need for saved regs to be in CmmCall. - -- The long term solution is to factor callerSaveVolatileRegs - -- from nativeGen into CPS - -- The format for the call to a continuation -- The fst is the arguments that must be passed to the continuation -- by the continuation's caller. @@ -54,7 +57,7 @@ data Continuation info = info -- Left <=> Continuation created by the CPS -- Right <=> Function or Proc point CLabel -- Used to generate both info & entry labels - CmmFormals -- Argument locals live on entry (C-- procedure params) + CmmFormalsWithoutKinds -- Argument locals live on entry (C-- procedure params) Bool -- ^ True <=> GC block so ignore stack size [BrokenBlock] -- Code, may be empty. The first block is -- the entry point. The order is otherwise initially @@ -67,7 +70,7 @@ data Continuation info = data ContinuationFormat = ContinuationFormat { - continuation_formals :: CmmFormals, + continuation_formals :: CmmFormalsWithoutKinds, continuation_label :: Maybe CLabel, -- The label occupying the top slot continuation_frame_size :: WordOff, -- Total frame size in words (not including arguments) continuation_stack :: [Maybe LocalReg] -- local reg offsets from stack top @@ -80,13 +83,15 @@ data ContinuationFormat ----------------------------------------------------------------------------- continuationToProc :: (WordOff, WordOff, [(CLabel, ContinuationFormat)]) -> CmmReg - -> [[Unique]] + -> [[[Unique]]] -> Continuation CmmInfo -> CmmTop continuationToProc (max_stack, update_frame_size, formats) stack_use uniques (Continuation info label formals _ blocks) = - CmmProc info label formals (concat $ zipWith3 continuationToProc' uniques blocks (True : repeat False)) + CmmProc info label formals (ListGraph blocks') where + blocks' = concat $ zipWith3 continuationToProc' uniques blocks + (True : repeat False) curr_format = maybe unknown_block id $ lookup label formats unknown_block = panic "unknown BlockId in continuationToProc" curr_stack = continuation_frame_size curr_format @@ -97,11 +102,7 @@ continuationToProc (max_stack, update_frame_size, formats) stack_use uniques gc_stmts :: [CmmStmt] gc_stmts = - case info of - CmmInfo (Just gc_block) _ _ -> - gc_stack_check' stack_use arg_stack (max_stack - curr_stack) - CmmInfo Nothing _ _ -> - panic "continuationToProc: missing GC block" + assign_gc_stack_use stack_use arg_stack (max_stack - curr_stack) update_stmts :: [CmmStmt] update_stmts = @@ -111,28 +112,30 @@ continuationToProc (max_stack, update_frame_size, formats) stack_use uniques adjust_sp_reg (curr_stack - update_frame_size) CmmInfo _ Nothing _ -> [] --- At present neither the Cmm parser nor the code generator --- produce code that will allow the target of a CmmCondBranch --- or a CmmSwitch to become a continuation or a proc-point. --- If future revisions, might allow these to happen --- then special care will have to be take to allow for that case. - continuationToProc' :: [Unique] + continuationToProc' :: [[Unique]] -> BrokenBlock -> Bool -> [CmmBasicBlock] continuationToProc' uniques (BrokenBlock ident entry stmts _ exit) is_entry = - prefix_blocks ++ [main_block] + prefix_blocks ++ [BasicBlock ident fixed_main_stmts] ++ concat new_blocks where prefix_blocks = - case gc_prefix ++ param_prefix of - [] -> [] - entry_stmts -> [BasicBlock prefix_id - (entry_stmts ++ [CmmBranch ident])] + if is_entry + then [BasicBlock + (BlockId prefix_unique) + (param_stmts ++ [CmmBranch ident])] + else [] - prefix_unique : call_uniques = uniques + (prefix_unique : call_uniques) : new_block_uniques = uniques toCLabel = mkReturnPtLabel . getUnique + block_for_branch :: Unique -> BlockId -> (BlockId, [CmmBasicBlock]) block_for_branch unique next + -- branches to the current function don't have to jump + | (mkReturnPtLabel $ getUnique next) == label + = (next, []) + + -- branches to any other function have to jump | (Just cont_format) <- lookup (toCLabel next) formats = let new_next = BlockId unique @@ -140,19 +143,38 @@ continuationToProc (max_stack, update_frame_size, formats) stack_use uniques arguments = map formal_to_actual (continuation_formals cont_format) in (new_next, [BasicBlock new_next $ - pack_continuation False curr_format cont_format ++ + pack_continuation curr_format cont_format ++ tail_call (curr_stack - cont_stack) (CmmLit $ CmmLabel $ toCLabel next) arguments]) + + -- branches to blocks in the current function don't have to jump | otherwise = (next, []) + -- Wrapper for block_for_branch for when the target + -- is inside a 'Maybe'. block_for_branch' :: Unique -> Maybe BlockId -> (Maybe BlockId, [CmmBasicBlock]) block_for_branch' _ Nothing = (Nothing, []) block_for_branch' unique (Just next) = (Just new_next, new_blocks) where (new_next, new_blocks) = block_for_branch unique next - main_block = + -- If the target of a switch, branch or cond branch becomes a proc point + -- then we have to make a new block what will then *jump* to the original target. + proc_point_fix unique (CmmCondBranch test target) + = (CmmCondBranch test new_target, new_blocks) + where (new_target, new_blocks) = block_for_branch (head unique) target + proc_point_fix unique (CmmSwitch test targets) + = (CmmSwitch test new_targets, concat new_blocks) + where (new_targets, new_blocks) = + unzip $ zipWith block_for_branch' unique targets + proc_point_fix unique (CmmBranch target) + = (CmmBranch new_target, new_blocks) + where (new_target, new_blocks) = block_for_branch (head unique) target + proc_point_fix _ other = (other, []) + + (fixed_main_stmts, new_blocks) = unzip $ zipWith proc_point_fix new_block_uniques main_stmts + main_stmts = case entry of FunctionEntry _ _ _ -> -- Ugh, the statements for an update frame must come @@ -161,43 +183,28 @@ continuationToProc (max_stack, update_frame_size, formats) stack_use uniques -- a bit. This depends on the knowledge that the -- statements in the first block are only the GC check. -- That's fragile but it works for now. - BasicBlock ident (stmts ++ update_stmts ++ postfix_stmts) - ControlEntry -> BasicBlock ident (stmts ++ postfix_stmts) - ContinuationEntry _ _ _ -> BasicBlock ident (stmts ++ postfix_stmts) - prefix_id = BlockId prefix_unique - gc_prefix = case entry of - FunctionEntry _ _ _ -> gc_stmts - ControlEntry -> [] - ContinuationEntry _ _ _ -> [] - param_prefix = if is_entry - then param_stmts - else [] + gc_stmts ++ stmts ++ update_stmts ++ postfix_stmts + ControlEntry -> stmts ++ postfix_stmts + ContinuationEntry _ _ _ -> stmts ++ postfix_stmts postfix_stmts = case exit of - FinalBranch next -> - if (mkReturnPtLabel $ getUnique next) == label - then [CmmBranch next] - else case lookup (mkReturnPtLabel $ getUnique next) formats of - Nothing -> [CmmBranch next] - Just cont_format -> - pack_continuation False curr_format cont_format ++ - tail_call (curr_stack - cont_stack) - (CmmLit $ CmmLabel $ mkReturnPtLabel $ getUnique next) - arguments - where - cont_stack = continuation_frame_size cont_format - arguments = map formal_to_actual (continuation_formals cont_format) + -- Branches and switches may get modified by proc_point_fix + FinalBranch next -> [CmmBranch next] FinalSwitch expr targets -> [CmmSwitch expr targets] + + -- A return is a tail call to the stack top FinalReturn arguments -> tail_call curr_stack - (CmmLoad (CmmReg spReg) wordRep) + (entryCode (CmmLoad (CmmReg spReg) wordRep)) arguments + + -- A tail call FinalJump target arguments -> tail_call curr_stack target arguments -- A regular Cmm function call - FinalCall next (CmmForeignCall target CmmCallConv) - results arguments _ _ -> - pack_continuation True curr_format cont_format ++ + FinalCall next (CmmCallee target CmmCallConv) + results arguments _ _ _ -> + pack_continuation curr_format cont_format ++ tail_call (curr_stack - cont_stack) target arguments where @@ -206,10 +213,10 @@ continuationToProc (max_stack, update_frame_size, formats) stack_use uniques cont_stack = continuation_frame_size cont_format -- A safe foreign call - FinalCall next (CmmForeignCall target conv) - results arguments _ _ -> + FinalCall next (CmmCallee target conv) + results arguments _ _ _ -> target_stmts ++ - foreignCall call_uniques' (CmmForeignCall new_target conv) + foreignCall call_uniques' (CmmCallee new_target conv) results arguments where (call_uniques', target_stmts, new_target) = @@ -217,46 +224,48 @@ continuationToProc (max_stack, update_frame_size, formats) stack_use uniques -- A safe prim call FinalCall next (CmmPrim target) - results arguments _ _ -> + results arguments _ _ _ -> foreignCall call_uniques (CmmPrim target) results arguments -formal_to_actual reg = (CmmReg (CmmLocal reg), NoHint) +formal_to_actual reg = CmmKinded (CmmReg (CmmLocal reg)) NoHint -foreignCall :: [Unique] -> CmmCallTarget -> CmmHintFormals -> CmmActuals -> [CmmStmt] +foreignCall :: [Unique] -> CmmCallTarget -> CmmFormals -> CmmActuals -> [CmmStmt] foreignCall uniques call results arguments = arg_stmts ++ saveThreadState ++ caller_save ++ - [CmmCall (CmmForeignCall suspendThread CCallConv) - [ (id,PtrHint) ] - [ (CmmReg (CmmGlobal BaseReg), PtrHint) ] - CmmUnsafe, - CmmCall call results new_args CmmUnsafe, - CmmCall (CmmForeignCall resumeThread CCallConv) - [ (new_base, PtrHint) ] - [ (CmmReg (CmmLocal id), PtrHint) ] - CmmUnsafe, + [CmmCall (CmmCallee suspendThread CCallConv) + [ CmmKinded id PtrHint ] + [ CmmKinded (CmmReg (CmmGlobal BaseReg)) PtrHint ] + CmmUnsafe + CmmMayReturn, + CmmCall call results new_args CmmUnsafe CmmMayReturn, + CmmCall (CmmCallee resumeThread CCallConv) + [ CmmKinded new_base PtrHint ] + [ CmmKinded (CmmReg (CmmLocal id)) PtrHint ] + CmmUnsafe + CmmMayReturn, -- Assign the result to BaseReg: we -- might now have a different Capability! CmmAssign (CmmGlobal BaseReg) (CmmReg (CmmLocal new_base))] ++ caller_load ++ loadThreadState tso_unique ++ - [CmmJump (CmmReg spReg) (map (formal_to_actual . fst) results)] + [CmmJump (CmmReg spReg) (map (formal_to_actual . kindlessCmm) results)] where (_, arg_stmts, new_args) = loadArgsIntoTemps argument_uniques arguments (caller_save, caller_load) = callerSaveVolatileRegs (Just [{-only system regs-}]) - new_base = LocalReg base_unique (cmmRegRep (CmmGlobal BaseReg)) KindNonPtr - id = LocalReg id_unique wordRep KindNonPtr + new_base = LocalReg base_unique (cmmRegRep (CmmGlobal BaseReg)) GCKindNonPtr + id = LocalReg id_unique wordRep GCKindNonPtr tso_unique : base_unique : id_unique : argument_uniques = uniques -- ----------------------------------------------------------------------------- -- Save/restore the thread state in the TSO -suspendThread = CmmLit (CmmLabel (mkRtsCodeLabel SLIT("suspendThread"))) -resumeThread = CmmLit (CmmLabel (mkRtsCodeLabel SLIT("resumeThread"))) +suspendThread = CmmLit (CmmLabel (mkRtsCodeLabel (sLit "suspendThread"))) +resumeThread = CmmLit (CmmLabel (mkRtsCodeLabel (sLit "resumeThread"))) -- This stuff can't be done in suspendThread/resumeThread, because it -- refers to global registers which aren't available in the C world. @@ -290,7 +299,7 @@ loadThreadState tso_unique = then [CmmStore curCCSAddr (CmmLoad (cmmOffset (CmmReg (CmmLocal tso)) tso_CCCS) wordRep)] else [] - where tso = LocalReg tso_unique wordRep KindNonPtr -- TODO FIXME NOW + where tso = LocalReg tso_unique wordRep GCKindNonPtr -- TODO FIXME NOW openNursery = [ @@ -354,19 +363,19 @@ tail_call spRel target arguments = store_arguments ++ adjust_sp_reg spRel ++ jump where store_arguments = [stack_put spRel expr offset - | ((expr, _), StackParam offset) <- argument_formats] ++ + | ((CmmKinded expr _), StackParam offset) <- argument_formats] ++ [global_put expr global - | ((expr, _), RegisterParam global) <- argument_formats] + | ((CmmKinded expr _), RegisterParam global) <- argument_formats] jump = [CmmJump target arguments] - argument_formats = assignArguments (cmmExprRep . fst) arguments + argument_formats = assignArguments (cmmExprRep . kindlessCmm) arguments adjust_sp_reg spRel = if spRel == 0 then [] else [CmmAssign spReg (CmmRegOff spReg (spRel*wORD_SIZE))] -gc_stack_check' stack_use arg_stack max_frame_size = +assign_gc_stack_use stack_use arg_stack max_frame_size = if max_frame_size > arg_stack then [CmmAssign stack_use (CmmRegOff spReg (-max_frame_size*wORD_SIZE))] else [CmmAssign stack_use (CmmReg spLimReg)] @@ -383,20 +392,13 @@ gc_stack_check gc_block max_frame_size gc_block] -pack_continuation :: Bool -- ^ Whether to set the top/header - -- of the stack. We only need to - -- set it if we are calling down - -- as opposed to continuation - -- adaptors. - -> ContinuationFormat -- ^ The current format +pack_continuation :: ContinuationFormat -- ^ The current format -> ContinuationFormat -- ^ The return point format -> [CmmStmt] -pack_continuation allow_header_set - (ContinuationFormat _ curr_id curr_frame_size _) - (ContinuationFormat _ cont_id cont_frame_size live_regs) +pack_continuation (ContinuationFormat _ curr_id curr_frame_size _) + (ContinuationFormat _ cont_id cont_frame_size live_regs) = pack_frame curr_frame_size cont_frame_size maybe_header continuation_args where - continuation_function = CmmLit $ CmmLabel $ fromJust cont_id continuation_args = map (maybe Nothing (Just . CmmReg . CmmLocal)) live_regs needs_header_set = @@ -404,8 +406,8 @@ pack_continuation allow_header_set (Just x, Just y) -> x /= y _ -> isJust cont_id - maybe_header = if allow_header_set && needs_header_set - then Just continuation_function + maybe_header = if needs_header_set + then maybe Nothing (Just . CmmLit . CmmLabel . entryLblToInfoLbl) cont_id else Nothing pack_frame :: WordOff -- ^ Current frame size