X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=blobdiff_plain;f=compiler%2FcodeGen%2FCgInfoTbls.hs;h=3d28a587b9aa017d5cdcec79d1d513493210bf42;hp=1c30d066c199d08f240d51a1b3005c2759356466;hb=ad94d40948668032189ad22a0ad741ac1f645f50;hpb=80564ddc183ea98856994112858f0b9f3e178f94 diff --git a/compiler/codeGen/CgInfoTbls.hs b/compiler/codeGen/CgInfoTbls.hs index 1c30d06..3d28a58 100644 --- a/compiler/codeGen/CgInfoTbls.hs +++ b/compiler/codeGen/CgInfoTbls.hs @@ -6,23 +6,26 @@ -- ----------------------------------------------------------------------------- +{-# 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/CodingStyle#Warnings +-- for details + module CgInfoTbls ( emitClosureCodeAndInfoTable, emitInfoTableAndCode, dataConTagZ, - getSRTInfo, - emitDirectReturnTarget, emitAlgReturnTarget, - emitDirectReturnInstr, emitVectoredReturnInstr, - mkRetInfoTable, - mkStdInfoTable, + emitReturnTarget, emitAlgReturnTarget, + emitReturnInstr, stdInfoTableSizeB, - mkFunGenInfoExtraBits, entryCode, closureInfoPtr, getConstrTag, + cmmGetClosureType, infoTable, infoTableClosureType, infoTablePtrs, infoTableNonPtrs, - funInfoTable, - retVec + funInfoTable, makeRelativeRefTo ) where @@ -43,12 +46,13 @@ import StgSyn import Name import DataCon import Unique -import DynFlags import StaticFlags -import ListSetOps import Maybes import Constants +import Panic +import Util +import Outputable ------------------------------------------------------------------------- -- @@ -56,103 +60,78 @@ import Constants -- ------------------------------------------------------------------------- --- Here we make a concrete info table, represented as a list of CmmAddr --- (it can't be simply a list of Word, because the SRT field is --- represented by a label+offset expression). - --- With tablesNextToCode, the layout is --- --- --- --- --- Without tablesNextToCode, the layout of an info table is --- --- --- --- --- See includes/InfoTables.h +-- Here we make an info table of type 'CmmInfo'. The concrete +-- representation as a list of 'CmmAddr' is handled later +-- in the pipeline by 'cmmToRawCmm'. -emitClosureCodeAndInfoTable :: ClosureInfo -> [LocalReg] -> CgStmts -> Code +emitClosureCodeAndInfoTable :: ClosureInfo -> CmmFormals -> CgStmts -> Code emitClosureCodeAndInfoTable cl_info args body - = do { ty_descr_lit <- - if opt_SccProfilingOn - then mkStringCLit (closureTypeDescr cl_info) - else return (mkIntCLit 0) - ; cl_descr_lit <- - if opt_SccProfilingOn - then mkStringCLit cl_descr_string - else return (mkIntCLit 0) - ; let std_info = mkStdInfoTable ty_descr_lit cl_descr_lit - cl_type srt_len layout_lit - - ; blks <- cgStmtsToBlocks body - ; emitInfoTableAndCode info_lbl std_info extra_bits args blks } + = do { blks <- cgStmtsToBlocks body + ; info <- mkCmmInfo cl_info + ; emitInfoTableAndCode (infoLblToEntryLbl info_lbl) info args blks } where info_lbl = infoTableLabelFromCI cl_info - cl_descr_string = closureValDescr cl_info - cl_type = smRepClosureTypeInt (closureSMRep cl_info) - - srt = closureSRT cl_info - needs_srt = needsSRT srt - - mb_con = isConstrClosure_maybe cl_info - is_con = isJust mb_con - - (srt_label,srt_len) - = case mb_con of - Just con -> -- Constructors don't have an SRT - -- We keep the *zero-indexed* tag in the srt_len - -- field of the info table. - (mkIntCLit 0, fromIntegral (dataConTagZ con)) - - Nothing -> -- Not a constructor - srtLabelAndLength srt info_lbl - - ptrs = closurePtrsSize cl_info - nptrs = size - ptrs - size = closureNonHdrSize cl_info - layout_lit = packHalfWordsCLit ptrs nptrs - - extra_bits - | is_fun = fun_extra_bits - | is_con = [] - | needs_srt = [srt_label] - | otherwise = [] - - maybe_fun_stuff = closureFunInfo cl_info - is_fun = isJust maybe_fun_stuff - (Just (arity, arg_descr)) = maybe_fun_stuff - - fun_extra_bits - | ArgGen liveness <- arg_descr - = [ fun_amode, - srt_label, - makeRelativeRefTo info_lbl $ mkLivenessCLit liveness, - slow_entry ] - | needs_srt = [fun_amode, srt_label] - | otherwise = [fun_amode] - - slow_entry = makeRelativeRefTo info_lbl (CmmLabel slow_entry_label) - slow_entry_label = mkSlowEntryLabel (closureName cl_info) - - fun_amode = packHalfWordsCLit fun_type arity - fun_type = argDescrType arg_descr - -- We keep the *zero-indexed* tag in the srt_len field of the info -- table of a data constructor. dataConTagZ :: DataCon -> ConTagZ dataConTagZ con = dataConTag con - fIRST_TAG --- A low-level way to generate the variable part of a fun-style info table. --- (must match fun_extra_bits above). Used by the C-- parser. -mkFunGenInfoExtraBits :: Int -> Int -> CmmLit -> CmmLit -> CmmLit -> [CmmLit] -mkFunGenInfoExtraBits fun_type arity srt_label liveness slow_entry - = [ packHalfWordsCLit fun_type arity, - srt_label, - liveness, - slow_entry ] +-- Convert from 'ClosureInfo' to 'CmmInfo'. +-- Not used for return points. (The 'smRepClosureTypeInt' call would panic.) +mkCmmInfo :: ClosureInfo -> FCode CmmInfo +mkCmmInfo cl_info = do + prof <- + if opt_SccProfilingOn + then do ty_descr_lit <- mkStringCLit (closureTypeDescr cl_info) + cl_descr_lit <- mkStringCLit (closureValDescr cl_info) + return $ ProfilingInfo ty_descr_lit cl_descr_lit + else return $ ProfilingInfo (mkIntCLit 0) (mkIntCLit 0) + + case cl_info of + ConInfo { closureCon = con } -> do + cstr <- mkByteStringCLit $ dataConIdentity con + let conName = makeRelativeRefTo info_lbl cstr + info = ConstrInfo (ptrs, nptrs) + (fromIntegral (dataConTagZ con)) + conName + return $ CmmInfo gc_target Nothing (CmmInfoTable prof cl_type info) + + ClosureInfo { closureName = name, + closureLFInfo = lf_info, + closureSRT = srt } -> + return $ CmmInfo gc_target Nothing (CmmInfoTable prof cl_type info) + where + info = + case lf_info of + LFReEntrant _ arity _ arg_descr -> + FunInfo (ptrs, nptrs) + srt + (argDescrType arg_descr) + (fromIntegral arity) + arg_descr + (CmmLabel (mkSlowEntryLabel name)) + LFThunk _ _ _ (SelectorThunk offset) _ -> + ThunkSelectorInfo (fromIntegral offset) srt + LFThunk _ _ _ _ _ -> + ThunkInfo (ptrs, nptrs) srt + _ -> panic "unexpected lambda form in mkCmmInfo" + where + info_lbl = infoTableLabelFromCI cl_info + + cl_type = smRepClosureTypeInt (closureSMRep cl_info) + + ptrs = fromIntegral $ closurePtrsSize cl_info + size = fromIntegral $ closureNonHdrSize cl_info + nptrs = size - ptrs + + -- The gc_target is to inform the CPS pass when it inserts a stack check. + -- Since that pass isn't used yet we'll punt for now. + -- When the CPS pass is fully integrated, this should + -- be replaced by the label that any heap check jumped to, + -- so that branch can be shared by both the heap (from codeGen) + -- and stack checks (from the CPS pass). + gc_target = panic "TODO: gc_target" ------------------------------------------------------------------------- -- @@ -160,237 +139,176 @@ mkFunGenInfoExtraBits fun_type arity srt_label liveness slow_entry -- ------------------------------------------------------------------------- --- Here's the layout of a return-point info table --- --- Tables next to code: --- --- --- --- --- ret-addr --> --- --- Not tables-next-to-code: --- --- ret-addr --> --- --- --- --- --- * The vector table is only present for vectored returns --- --- * The SRT slot is only there if either --- (a) there is SRT info to record, OR --- (b) if the return is vectored --- The latter (b) is necessary so that the vector is in a --- predictable place - -vectorSlot :: CmmExpr -> CmmExpr -> CmmExpr --- Get the vector slot from the info pointer -vectorSlot info_amode zero_indexed_tag - | tablesNextToCode - = cmmOffsetExprW (cmmOffsetW info_amode (- (stdInfoTableSizeW + 2))) - (cmmNegate zero_indexed_tag) - -- The "2" is one for the SRT slot, and one more - -- to get to the first word of the vector - - | otherwise - = cmmOffsetExprW (cmmOffsetW info_amode (stdInfoTableSizeW + 2)) - zero_indexed_tag - -- The "2" is one for the entry-code slot and one for the SRT slot - -retVec :: CmmExpr -> CmmExpr -> CmmExpr --- Get a return vector from the info pointer -retVec info_amode zero_indexed_tag - = let slot = vectorSlot info_amode zero_indexed_tag - table_slot = CmmLoad slot wordRep -#if defined(x86_64_TARGET_ARCH) - offset_slot = CmmMachOp (MO_S_Conv I32 I64) [CmmLoad slot I32] - -- offsets are 32-bits on x86-64, due to the inability of - -- the tools to handle 64-bit PC-relative relocations. See also - -- PprMach.pprDataItem, and InfoTables.h:OFFSET_FIELD(). -#else - offset_slot = table_slot -#endif - in if tablesNextToCode - then CmmMachOp (MO_Add wordRep) [offset_slot, info_amode] - else table_slot +-- The concrete representation as a list of 'CmmAddr' is handled later +-- in the pipeline by 'cmmToRawCmm'. emitReturnTarget :: Name -> CgStmts -- The direct-return code (if any) - -- (empty for vectored returns) - -> [CmmLit] -- Vector of return points - -- (empty for non-vectored returns) - -> SRT -> FCode CLabel -emitReturnTarget name stmts vector srt - = do { live_slots <- getLiveStackSlots - ; liveness <- buildContLiveness name live_slots - ; srt_info <- getSRTInfo name srt - - ; let - cl_type = case (null vector, isBigLiveness liveness) of - (True, True) -> rET_BIG - (True, False) -> rET_SMALL - (False, True) -> rET_VEC_BIG - (False, False) -> rET_VEC_SMALL - - (std_info, extra_bits) = - mkRetInfoTable info_lbl liveness srt_info cl_type vector - +emitReturnTarget name stmts + = do { srt_info <- getSRTInfo ; blks <- cgStmtsToBlocks stmts - ; emitInfoTableAndCode info_lbl std_info extra_bits args blks + ; frame <- mkStackLayout + ; let info = CmmInfo + gc_target + Nothing + (CmmInfoTable + (ProfilingInfo zeroCLit zeroCLit) + rET_SMALL -- cmmToRawCmm may convert it to rET_BIG + (ContInfo frame srt_info)) + ; emitInfoTableAndCode (infoLblToEntryLbl info_lbl) info args blks ; return info_lbl } where args = {- trace "emitReturnTarget: missing args" -} [] uniq = getUnique name info_lbl = mkReturnInfoLabel uniq + -- The gc_target is to inform the CPS pass when it inserts a stack check. + -- Since that pass isn't used yet we'll punt for now. + -- When the CPS pass is fully integrated, this should + -- be replaced by the label that any heap check jumped to, + -- so that branch can be shared by both the heap (from codeGen) + -- and stack checks (from the CPS pass). + gc_target = panic "TODO: gc_target" + -mkRetInfoTable - :: CLabel -- info label - -> Liveness -- liveness - -> C_SRT -- SRT Info - -> Int -- type (eg. rET_SMALL) - -> [CmmLit] -- vector - -> ([CmmLit],[CmmLit]) -mkRetInfoTable info_lbl liveness srt_info cl_type vector - = (std_info, extra_bits) +-- Build stack layout information from the state of the 'FCode' monad. +-- Should go away once 'codeGen' starts using the CPS conversion +-- pass to handle the stack. Until then, this is really just +-- here to convert from the 'codeGen' representation of the stack +-- to the 'CmmInfo' representation of the stack. +-- +-- See 'CmmInfo.mkLiveness' for where this is converted to a bitmap. + +{- +This seems to be a very error prone part of the code. +It is surprisingly prone to off-by-one errors, because +it converts between offset form (codeGen) and list form (CmmInfo). +Thus a bit of explanation is in order. +Fortunately, this code should go away once the code generator +starts using the CPS conversion pass to handle the stack. + +The stack looks like this: + + | | + |-------------| +frame_sp --> | return addr | + |-------------| + | dead slot | + |-------------| + | live ptr b | + |-------------| + | live ptr a | + |-------------| +real_sp --> | return addr | + +-------------+ + +Both 'frame_sp' and 'real_sp' are measured downwards +(i.e. larger frame_sp means smaller memory address). + +For that frame we want a result like: [Just a, Just b, Nothing] +Note that the 'head' of the list is the top +of the stack, and that the return address +is not present in the list (it is always assumed). +-} +mkStackLayout :: FCode [Maybe LocalReg] +mkStackLayout = do + StackUsage { realSp = real_sp, + frameSp = frame_sp } <- getStkUsage + binds <- getLiveStackBindings + let frame_size = real_sp - frame_sp - retAddrSizeW + rel_binds = reverse $ sortWith fst + [(offset - frame_sp - retAddrSizeW, b) + | (offset, b) <- binds] + + WARN( not (all (\bind -> fst bind >= 0) rel_binds), + ppr binds $$ ppr rel_binds $$ + ppr frame_size $$ ppr real_sp $$ ppr frame_sp ) + return $ stack_layout rel_binds frame_size + +stack_layout :: [(VirtualSpOffset, CgIdInfo)] + -> WordOff + -> [Maybe LocalReg] +stack_layout [] sizeW = replicate sizeW Nothing +stack_layout ((off, bind):binds) sizeW | off == sizeW - 1 = + (Just stack_bind) : (stack_layout binds (sizeW - rep_size)) where - (srt_label, srt_len) = srtLabelAndLength srt_info info_lbl - - srt_slot | need_srt = [srt_label] - | otherwise = [] - - need_srt = needsSRT srt_info || not (null vector) - -- If there's a vector table then we must allocate - -- an SRT slot, so that the vector table is at a - -- known offset from the info pointer - - liveness_lit = makeRelativeRefTo info_lbl $ mkLivenessCLit liveness - std_info = mkStdInfoTable zeroCLit zeroCLit cl_type srt_len liveness_lit - extra_bits = srt_slot ++ map (makeRelativeRefTo info_lbl) vector - - -emitDirectReturnTarget - :: Name - -> CgStmts -- The direct-return code - -> SRT - -> FCode CLabel -emitDirectReturnTarget name code srt - = emitReturnTarget name code [] srt + rep_size = cgRepSizeW (cgIdInfoArgRep bind) + stack_bind = LocalReg unique machRep kind + unique = getUnique (cgIdInfoId bind) + machRep = argMachRep (cgIdInfoArgRep bind) + kind = if isFollowableArg (cgIdInfoArgRep bind) + then KindPtr + else KindNonPtr +stack_layout binds@((off, _):_) sizeW | otherwise = + Nothing : (stack_layout binds (sizeW - 1)) + +{- Another way to write the function that might be less error prone (untested) +stack_layout offsets sizeW = result + where + y = map (flip lookup offsets) [0..] + -- offsets -> nothing and just (each slot is one word) + x = take sizeW y -- set the frame size + z = clip x -- account for multi-word slots + result = map mk_reg z + + clip [] = [] + clip list@(x : _) = x : clip (drop count list) + ASSERT(all isNothing (tail (take count list))) + + count Nothing = 1 + count (Just x) = cgRepSizeW (cgIdInfoArgRep x) + + mk_reg Nothing = Nothing + mk_reg (Just x) = LocalReg unique machRep kind + where + unique = getUnique (cgIdInfoId x) + machRep = argMachrep (cgIdInfoArgRep bind) + kind = if isFollowableArg (cgIdInfoArgRep bind) + then KindPtr + else KindNonPtr +-} emitAlgReturnTarget :: Name -- Just for its unique -> [(ConTagZ, CgStmts)] -- Tagged branches -> Maybe CgStmts -- Default branch (if any) - -> SRT -- Continuation's SRT - -> CtrlReturnConvention + -> Int -- family size -> FCode (CLabel, SemiTaggingStuff) -emitAlgReturnTarget name branches mb_deflt srt ret_conv - = case ret_conv of - UnvectoredReturn fam_sz -> do - { blks <- getCgStmts $ - emitSwitch tag_expr branches mb_deflt 0 (fam_sz - 1) - -- NB: tag_expr is zero-based - ; lbl <- emitDirectReturnTarget name blks srt +emitAlgReturnTarget name branches mb_deflt fam_sz + = do { blks <- getCgStmts $ + -- is the constructor tag in the node reg? + if isSmallFamily fam_sz + then do -- yes, node has constr. tag + let tag_expr = cmmConstrTag1 (CmmReg nodeReg) + branches' = [(tag+1,branch)|(tag,branch)<-branches] + emitSwitch tag_expr branches' mb_deflt 1 fam_sz + else do -- no, get tag from info table + let -- Note that ptr _always_ has tag 1 + -- when the family size is big enough + untagged_ptr = cmmRegOffB nodeReg (-1) + tag_expr = getConstrTag (untagged_ptr) + emitSwitch tag_expr branches mb_deflt 0 (fam_sz - 1) + ; lbl <- emitReturnTarget name blks ; return (lbl, Nothing) } -- Nothing: the internal branches in the switch don't have -- global labels, so we can't use them at the 'call site' - - VectoredReturn fam_sz -> do - { let tagged_lbls = zip (map fst branches) $ - map (CmmLabel . mkAltLabel uniq . fst) branches - deflt_lbl | isJust mb_deflt = CmmLabel $ mkDefaultLabel uniq - | otherwise = mkIntCLit 0 - ; let vector = [ assocDefault deflt_lbl tagged_lbls i - | i <- [0..fam_sz-1]] - ; lbl <- emitReturnTarget name noCgStmts vector srt - ; mapFCs emit_alt branches - ; emit_deflt mb_deflt - ; return (lbl, Just (tagged_lbls, deflt_lbl)) } where uniq = getUnique name - tag_expr = getConstrTag (CmmReg nodeReg) - - emit_alt :: (Int, CgStmts) -> FCode (Int, CmmLit) - -- Emit the code for the alternative as a top-level - -- code block returning a label for it - emit_alt (tag, stmts) = do { let lbl = mkAltLabel uniq tag - ; blks <- cgStmtsToBlocks stmts - ; emitProc [] lbl [] blks - ; return (tag, CmmLabel lbl) } - - emit_deflt (Just stmts) = do { let lbl = mkDefaultLabel uniq - ; blks <- cgStmtsToBlocks stmts - ; emitProc [] lbl [] blks - ; return (CmmLabel lbl) } - emit_deflt Nothing = return (mkIntCLit 0) - -- Nothing case: the simplifier might have eliminated a case - -- so we may have e.g. case xs of - -- [] -> e - -- In that situation the default should never be taken, - -- so we just use a NULL pointer -------------------------------- -emitDirectReturnInstr :: Code -emitDirectReturnInstr +emitReturnInstr :: Code +emitReturnInstr = do { info_amode <- getSequelAmode ; stmtC (CmmJump (entryCode info_amode) []) } -emitVectoredReturnInstr :: CmmExpr -- _Zero-indexed_ constructor tag - -> Code -emitVectoredReturnInstr zero_indexed_tag - = do { info_amode <- getSequelAmode - -- HACK! assign info_amode to a temp, because retVec - -- uses it twice and the NCG doesn't have any CSE yet. - -- Only do this for the NCG, because gcc is too stupid - -- to optimise away the extra tmp (grrr). - ; dflags <- getDynFlags - ; x <- if hscTarget dflags == HscAsm - then do z <- newTemp wordRep - stmtC (CmmAssign z info_amode) - return (CmmReg z) - else - return info_amode - ; let target = retVec x zero_indexed_tag - ; stmtC (CmmJump target []) } - - -------------------------------------------------------------------------- --- --- Generating a standard info table +----------------------------------------------------------------------------- -- -------------------------------------------------------------------------- - --- The standard bits of an info table. This part of the info table --- corresponds to the StgInfoTable type defined in InfoTables.h. +-- Info table offsets -- --- Its shape varies with ticky/profiling/tables next to code etc --- so we can't use constant offsets from Constants - -mkStdInfoTable - :: CmmLit -- closure type descr (profiling) - -> CmmLit -- closure descr (profiling) - -> Int -- closure type - -> StgHalfWord -- SRT length - -> CmmLit -- layout field - -> [CmmLit] - -mkStdInfoTable type_descr closure_descr cl_type srt_len layout_lit - = -- Parallel revertible-black hole field - prof_info - -- Ticky info (none at present) - -- Debug info (none at present) - ++ [layout_lit, type_lit] - - where - prof_info - | opt_SccProfilingOn = [type_descr, closure_descr] - | otherwise = [] - - type_lit = packHalfWordsCLit cl_type srt_len +----------------------------------------------------------------------------- stdInfoTableSizeW :: WordOff -- The size of a standard info table varies with profiling/ticky etc, @@ -444,6 +362,14 @@ getConstrTag closure_ptr where info_table = infoTable (closureInfoPtr closure_ptr) +cmmGetClosureType :: CmmExpr -> CmmExpr +-- Takes a closure pointer, and return the closure type +-- obtained from the info table +cmmGetClosureType closure_ptr + = CmmMachOp (MO_U_Conv halfWordRep wordRep) [infoTableClosureType info_table] + where + info_table = infoTable (closureInfoPtr closure_ptr) + infoTable :: CmmExpr -> CmmExpr -- Takes an info pointer (the first word of a closure) -- and returns a pointer to the first word of the standard-form @@ -499,31 +425,14 @@ funInfoTable info_ptr -- put the info table next to the code emitInfoTableAndCode - :: CLabel -- Label of info table - -> [CmmLit] -- ...its invariant part - -> [CmmLit] -- ...and its variant part - -> [LocalReg] -- ...args + :: CLabel -- Label of entry or ret + -> CmmInfo -- ...the info table + -> CmmFormals -- ...args -> [CmmBasicBlock] -- ...and body -> Code -emitInfoTableAndCode info_lbl std_info extra_bits args blocks - | tablesNextToCode -- Reverse the extra_bits; and emit the top-level proc - = emitProc (reverse extra_bits ++ std_info) - entry_lbl args blocks - -- NB: the info_lbl is discarded - - | null blocks -- No actual code; only the info table is significant - = -- Use a zero place-holder in place of the - -- entry-label in the info table - emitRODataLits info_lbl (zeroCLit : std_info ++ extra_bits) - - | otherwise -- Separately emit info table (with the function entry - = -- point as first entry) and the entry code - do { emitDataLits info_lbl (CmmLabel entry_lbl : std_info ++ extra_bits) - ; emitProc [] entry_lbl args blocks } - - where - entry_lbl = infoLblToEntryLbl info_lbl +emitInfoTableAndCode entry_ret_lbl info args blocks + = emitProc info entry_ret_lbl args blocks ------------------------------------------------------------------------- -- @@ -531,29 +440,6 @@ emitInfoTableAndCode info_lbl std_info extra_bits args blocks -- ------------------------------------------------------------------------- --- There is just one SRT for each top level binding; all the nested --- bindings use sub-sections of this SRT. The label is passed down to --- the nested bindings via the monad. - -getSRTInfo :: Name -> SRT -> FCode C_SRT -getSRTInfo id NoSRT = return NoC_SRT -getSRTInfo id (SRT off len bmp) - | len > hALF_WORD_SIZE_IN_BITS || bmp == [fromIntegral srt_escape] - = do { srt_lbl <- getSRTLabel - ; let srt_desc_lbl = mkSRTDescLabel id - ; emitRODataLits srt_desc_lbl - ( cmmLabelOffW srt_lbl off - : mkWordCLit (fromIntegral len) - : map mkWordCLit bmp) - ; return (C_SRT srt_desc_lbl 0 srt_escape) } - - | otherwise - = do { srt_lbl <- getSRTLabel - ; return (C_SRT srt_lbl off (fromIntegral (head bmp))) } - -- The fromIntegral converts to StgHalfWord - -srt_escape = (-1) :: StgHalfWord - srtLabelAndLength :: C_SRT -> CLabel -> (CmmLit, StgHalfWord) srtLabelAndLength NoC_SRT _ = (zeroCLit, 0)