+
+ -- A safe foreign call
+ FinalCall next (CmmForeignCall target conv)
+ results arguments _ _ ->
+ target_stmts ++
+ foreignCall call_uniques' (CmmForeignCall new_target conv)
+ results arguments
+ where
+ (call_uniques', target_stmts, new_target) =
+ maybeAssignTemp call_uniques target
+
+ -- A safe prim call
+ FinalCall next (CmmPrim target)
+ results arguments _ _ ->
+ foreignCall call_uniques (CmmPrim target)
+ results arguments
+
+formal_to_actual reg = (CmmReg (CmmLocal reg), NoHint)
+
+foreignCall :: [Unique] -> CmmCallTarget -> CmmHintFormals -> 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,
+ -- 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)]
+ 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
+ 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")))
+
+-- This stuff can't be done in suspendThread/resumeThread, because it
+-- refers to global registers which aren't available in the C world.
+
+saveThreadState =
+ -- CurrentTSO->sp = Sp;
+ [CmmStore (cmmOffset stgCurrentTSO tso_SP) stgSp,
+ closeNursery] ++
+ -- and save the current cost centre stack in the TSO when profiling:
+ if opt_SccProfilingOn
+ then [CmmStore (cmmOffset stgCurrentTSO tso_CCCS) curCCS]
+ else []
+
+ -- CurrentNursery->free = Hp+1;
+closeNursery = CmmStore nursery_bdescr_free (cmmOffsetW stgHp 1)
+
+loadThreadState tso_unique =
+ [
+ -- tso = CurrentTSO;
+ CmmAssign (CmmLocal tso) stgCurrentTSO,
+ -- Sp = tso->sp;
+ CmmAssign sp (CmmLoad (cmmOffset (CmmReg (CmmLocal tso)) tso_SP)
+ wordRep),
+ -- SpLim = tso->stack + RESERVED_STACK_WORDS;
+ CmmAssign spLim (cmmOffsetW (cmmOffset (CmmReg (CmmLocal tso)) tso_STACK)
+ rESERVED_STACK_WORDS)
+ ] ++
+ openNursery ++
+ -- and load the current cost centre stack from the TSO when profiling:
+ if opt_SccProfilingOn
+ then [CmmStore curCCSAddr
+ (CmmLoad (cmmOffset (CmmReg (CmmLocal tso)) tso_CCCS) wordRep)]
+ else []
+ where tso = LocalReg tso_unique wordRep KindNonPtr -- TODO FIXME NOW
+
+
+openNursery = [
+ -- Hp = CurrentNursery->free - 1;
+ CmmAssign hp (cmmOffsetW (CmmLoad nursery_bdescr_free wordRep) (-1)),
+
+ -- HpLim = CurrentNursery->start +
+ -- CurrentNursery->blocks*BLOCK_SIZE_W - 1;
+ CmmAssign hpLim
+ (cmmOffsetExpr
+ (CmmLoad nursery_bdescr_start wordRep)
+ (cmmOffset
+ (CmmMachOp mo_wordMul [
+ CmmMachOp (MO_S_Conv I32 wordRep)
+ [CmmLoad nursery_bdescr_blocks I32],
+ CmmLit (mkIntCLit bLOCK_SIZE)
+ ])
+ (-1)
+ )
+ )
+ ]
+
+
+nursery_bdescr_free = cmmOffset stgCurrentNursery oFFSET_bdescr_free
+nursery_bdescr_start = cmmOffset stgCurrentNursery oFFSET_bdescr_start
+nursery_bdescr_blocks = cmmOffset stgCurrentNursery oFFSET_bdescr_blocks
+
+tso_SP = tsoFieldB oFFSET_StgTSO_sp
+tso_STACK = tsoFieldB oFFSET_StgTSO_stack
+tso_CCCS = tsoProfFieldB oFFSET_StgTSO_CCCS
+
+-- The TSO struct has a variable header, and an optional StgTSOProfInfo in
+-- the middle. The fields we're interested in are after the StgTSOProfInfo.
+tsoFieldB :: ByteOff -> ByteOff
+tsoFieldB off
+ | opt_SccProfilingOn = off + sIZEOF_StgTSOProfInfo + fixedHdrSize * wORD_SIZE
+ | otherwise = off + fixedHdrSize * wORD_SIZE
+
+tsoProfFieldB :: ByteOff -> ByteOff
+tsoProfFieldB off = off + fixedHdrSize * wORD_SIZE
+
+stgSp = CmmReg sp
+stgHp = CmmReg hp
+stgCurrentTSO = CmmReg currentTSO
+stgCurrentNursery = CmmReg currentNursery
+
+sp = CmmGlobal Sp
+spLim = CmmGlobal SpLim
+hp = CmmGlobal Hp
+hpLim = CmmGlobal HpLim
+currentTSO = CmmGlobal CurrentTSO
+currentNursery = CmmGlobal CurrentNursery