------------------------------------------------------------------------------
-continuationToProc :: (WordOff, [(CLabel, ContinuationFormat)])
- -> CmmReg
- -> [Unique]
- -> Continuation CmmInfo
- -> CmmTop
-continuationToProc (max_stack, formats) stack_use uniques
- (Continuation info label formals _ blocks) =
- CmmProc info label formals (concat $ zipWith3 continuationToProc' uniques blocks (True : repeat False))
- where
- curr_format = maybe unknown_block id $ lookup label formats
- unknown_block = panic "unknown BlockId in continuationToProc"
- curr_stack = continuation_frame_size curr_format
- arg_stack = argumentsSize localRegRep formals
-
- param_stmts :: [CmmStmt]
- param_stmts = function_entry curr_format
-
- 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"
- CmmNonInfo (Just gc_block) ->
- gc_stack_check' stack_use arg_stack (max_stack - curr_stack)
- CmmNonInfo Nothing ->
- panic "continuationToProc: missing non-info GC block"
-
- continuationToProc' :: Unique -> BrokenBlock -> Bool -> [CmmBasicBlock]
- continuationToProc' unique (BrokenBlock ident entry stmts _ exit) is_entry =
- case gc_prefix ++ param_prefix of
- [] -> [main_block]
- stmts -> [BasicBlock prefix_id (gc_prefix ++ param_prefix ++ [CmmBranch ident]),
- main_block]
- where
- main_block = BasicBlock ident (stmts ++ postfix)
- prefix_id = BlockId unique
- gc_prefix = case entry of
- FunctionEntry _ _ _ -> gc_stmts
- ControlEntry -> []
- ContinuationEntry _ _ _ -> []
- param_prefix = if is_entry
- then param_stmts
- else []
- postfix = 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)
- formal_to_actual reg = (CmmReg (CmmLocal reg), NoHint)
- FinalSwitch expr targets -> [CmmSwitch expr targets]
- FinalReturn arguments ->
- tail_call curr_stack
- (CmmLoad (CmmReg spReg) wordRep)
- arguments
- FinalJump target arguments ->
- tail_call curr_stack target arguments
- FinalCall next (CmmForeignCall target CmmCallConv)
- results arguments _ _ ->
- pack_continuation True curr_format cont_format ++
- tail_call (curr_stack - cont_stack)
- target arguments
- where
- cont_format = maybe unknown_block id $
- lookup (mkReturnPtLabel $ getUnique next) formats
- cont_stack = continuation_frame_size cont_format
- FinalCall next _ results arguments _ _ -> panic "unimplemented CmmCall"
-
------------------------------------------------------------------------------
--- Functions that generate CmmStmt sequences
--- for packing/unpacking continuations
--- and entering/exiting functions
-
-tail_call :: WordOff -> CmmExpr -> CmmActuals -> [CmmStmt]
-tail_call spRel target arguments
- = store_arguments ++ adjust_spReg ++ jump where
- store_arguments =
- [stack_put spRel expr offset
- | ((expr, _), StackParam offset) <- argument_formats] ++
- [global_put expr global
- | ((expr, _), RegisterParam global) <- argument_formats]
- adjust_spReg =
- if spRel == 0
- then []
- else [CmmAssign spReg (CmmRegOff spReg (spRel*wORD_SIZE))]
- jump = [CmmJump target arguments]
-
- argument_formats = assignArguments (cmmExprRep . fst) arguments
-
-gc_stack_check' 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)]
- -- Trick the optimizer into eliminating the branch for us
-
-gc_stack_check :: BlockId -> WordOff -> [CmmStmt]
-gc_stack_check gc_block max_frame_size
- = check_stack_limit where
- check_stack_limit = [
- CmmCondBranch
- (CmmMachOp (MO_U_Lt $ cmmRegRep spReg)
- [CmmRegOff spReg (-max_frame_size*wORD_SIZE),
- CmmReg spLimReg])
- gc_block]
-
-
--- TODO: fix branches to proc point
--- (we have to insert a new block to marshel the continuation)
-pack_continuation :: Bool -> ContinuationFormat -> ContinuationFormat -> [CmmStmt]
-pack_continuation allow_header_set
- (ContinuationFormat _ curr_id curr_frame_size _)
- (ContinuationFormat _ cont_id cont_frame_size live_regs)
- = store_live_values ++ set_stack_header where
- -- TODO: only save variables when actually needed
- -- (may be handled by latter pass)
- store_live_values =
- [stack_put spRel (CmmReg (CmmLocal reg)) offset
- | (reg, offset) <- cont_offsets]
- set_stack_header =
- if needs_header_set && allow_header_set
- then [stack_put spRel continuation_function 0]
- else []
-
- -- TODO: factor with function_entry and CmmInfo.hs(?)
- cont_offsets = mkOffsets label_size live_regs
-
- label_size = 1 :: WordOff
-
- mkOffsets size [] = []
- mkOffsets size (Nothing:regs) = mkOffsets (size+1) regs
- mkOffsets size (Just reg:regs) = (reg, size):mkOffsets (size + width) regs
- where
- width = machRepByteWidth (localRegRep reg) `quot` wORD_SIZE
- -- TODO: it would be better if we had a machRepWordWidth
-
- spRel = curr_frame_size - cont_frame_size
- continuation_function = CmmLit $ CmmLabel $ fromJust cont_id
- needs_header_set =
- case (curr_id, cont_id) of
- (Just x, Just y) -> x /= y
- _ -> isJust cont_id
-
--- Lazy adjustment of stack headers assumes all blocks
--- that could branch to eachother (i.e. control blocks)
--- have the same stack format (this causes a problem
--- only for proc-point).
-function_entry :: ContinuationFormat -> [CmmStmt]
-function_entry (ContinuationFormat formals _ _ live_regs)
- = load_live_values ++ load_args where
- -- TODO: only save variables when actually needed
- -- (may be handled by latter pass)
- load_live_values =
- [stack_get 0 reg offset
- | (reg, offset) <- curr_offsets]
- load_args =
- [stack_get 0 reg offset
- | (reg, StackParam offset) <- argument_formats] ++
- [global_get reg global
- | (reg, RegisterParam global) <- argument_formats]
-
- argument_formats = assignArguments (localRegRep) formals
-
- -- TODO: eliminate copy/paste with pack_continuation
- curr_offsets = mkOffsets label_size live_regs
-
- label_size = 1 :: WordOff
-
- mkOffsets size [] = []
- mkOffsets size (Nothing:regs) = mkOffsets (size+1) regs
- mkOffsets size (Just reg:regs) = (reg, size):mkOffsets (size + width) regs
- where
- width = machRepByteWidth (localRegRep reg) `quot` wORD_SIZE
- -- TODO: it would be better if we had a machRepWordWidth
-
------------------------------------------------------------------------------
--- Section: Stack and argument register puts and gets
------------------------------------------------------------------------------
--- TODO: document
-
--- |Construct a 'CmmStmt' that will save a value on the stack
-stack_put :: WordOff -- ^ Offset from the real 'Sp' that 'offset'
- -- is relative to (added to offset)
- -> CmmExpr -- ^ What to store onto the stack
- -> WordOff -- ^ Where on the stack to store it
- -- (positive <=> higher addresses)
- -> CmmStmt
-stack_put spRel expr offset =
- CmmStore (CmmRegOff spReg (wORD_SIZE*(spRel + offset))) expr
-
---------------------------------
--- |Construct a
-stack_get :: WordOff
- -> LocalReg
- -> WordOff
- -> CmmStmt
-stack_get spRel reg offset =
- CmmAssign (CmmLocal reg)
- (CmmLoad (CmmRegOff spReg (wORD_SIZE*(spRel + offset)))
- (localRegRep reg))
-global_put :: CmmExpr -> GlobalReg -> CmmStmt
-global_put expr global = CmmAssign (CmmGlobal global) expr
-global_get :: LocalReg -> GlobalReg -> CmmStmt
-global_get reg global = CmmAssign (CmmLocal reg) (CmmReg (CmmGlobal global))
-