1 -----------------------------------------------------------------------------
3 -- Code generation for foreign calls.
5 -- (c) The University of Glasgow 2004
7 -----------------------------------------------------------------------------
13 emitSaveThreadState, -- will be needed by the Cmm parser
14 emitLoadThreadState, -- ditto
19 #include "HsVersions.h"
21 import StgSyn ( StgLiveVars, StgArg, stgArgType )
22 import CgProf ( curCCS, curCCSAddr )
23 import CgBindery ( getVolatileRegs, getArgAmodes )
25 import CgUtils ( cmmOffsetW, cmmOffsetB, cmmLoadIndexW, newTemp )
26 import Type ( tyConAppTyCon, repType )
28 import CLabel ( mkForeignLabel, mkRtsCodeLabel )
35 import CmdLineOpts ( opt_SccProfilingOn )
40 -- -----------------------------------------------------------------------------
41 -- Code generation for Foreign Calls
44 :: [(CmmReg,MachHint)] -- where to put the results
45 -> ForeignCall -- the op
46 -> [StgArg] -- arguments
47 -> StgLiveVars -- live vars, in case we need to save them
49 cgForeignCall results fcall stg_args live
51 reps_n_amodes <- getArgAmodes stg_args
53 -- Get the *non-void* args, and jiggle them with shimForeignCall
54 arg_exprs = [ shimForeignCallArg stg_arg expr
55 | (stg_arg, (rep,expr)) <- stg_args `zip` reps_n_amodes,
58 arg_hints = zip arg_exprs (map (typeHint.stgArgType) stg_args)
60 emitForeignCall results fcall arg_hints live
64 :: [(CmmReg,MachHint)] -- where to put the results
65 -> ForeignCall -- the op
66 -> [(CmmExpr,MachHint)] -- arguments
67 -> StgLiveVars -- live vars, in case we need to save them
70 emitForeignCall results (CCall (CCallSpec target cconv safety)) args live
71 | not (playSafe safety)
73 vols <- getVolatileRegs live
76 | otherwise -- it's a safe foreign call
78 vols <- getVolatileRegs live
81 stmtC (CmmCall (CmmForeignCall suspendThread CCallConv) [(id,NoHint)]
82 [ (CmmReg (CmmGlobal BaseReg), NoHint) ]
83 Nothing{-save all; ToDo-}
86 stmtC (CmmCall (CmmForeignCall resumeThread CCallConv) []
87 [ (CmmReg id, NoHint) ] (Just vols)
92 (call_args, cmm_target)
94 StaticTarget lbl -> (args, CmmLit (CmmLabel
95 (mkForeignLabel lbl call_size False)))
96 DynamicTarget -> case args of (fn,_):rest -> (rest, fn)
98 the_call vols = CmmCall (CmmForeignCall cmm_target cconv)
99 results call_args (Just vols)
101 -- in the stdcall calling convention, the symbol needs @size appended
102 -- to it, where size is the total number of bytes of arguments. We
103 -- attach this info to the CLabel here, and the CLabel pretty printer
104 -- will generate the suffix when the label is printed.
106 | StdCallConv <- cconv = Just (sum (map (arg_size.cmmExprRep.fst) args))
107 | otherwise = Nothing
109 -- ToDo: this might not be correct for 64-bit API
110 arg_size rep = max (machRepByteWidth rep) wORD_SIZE
113 emitForeignCall results (DNCall _) args live
114 = panic "emitForeignCall: DNCall"
116 suspendThread = CmmLit (CmmLabel (mkRtsCodeLabel SLIT("suspendThread")))
117 resumeThread = CmmLit (CmmLabel (mkRtsCodeLabel SLIT("resumeThread")))
119 -- -----------------------------------------------------------------------------
120 -- Save/restore the thread state in the TSO
122 -- This stuff can't be done in suspendThread/resumeThread, because it
123 -- refers to global registers which aren't available in the C world.
125 emitSaveThreadState = do
126 -- CurrentTSO->sp = Sp;
127 stmtC $ CmmStore (cmmOffset stgCurrentTSO tso_SP) stgSp
129 -- and save the current cost centre stack in the TSO when profiling:
130 when opt_SccProfilingOn $
131 stmtC (CmmStore (cmmOffset stgCurrentTSO tso_CCCS) curCCS)
133 -- CurrentNursery->free = Hp+1;
134 emitCloseNursery = stmtC $ CmmStore nursery_bdescr_free (cmmOffsetW stgHp 1)
136 emitLoadThreadState = do
137 tso <- newTemp wordRep
140 CmmAssign tso stgCurrentTSO,
142 CmmAssign sp (CmmLoad (cmmOffset (CmmReg tso) tso_SP)
144 -- SpLim = tso->stack + RESERVED_STACK_WORDS;
145 CmmAssign spLim (cmmOffsetW (cmmOffset (CmmReg tso) tso_STACK)
146 rESERVED_STACK_WORDS)
149 -- and load the current cost centre stack from the TSO when profiling:
150 when opt_SccProfilingOn $
151 stmtC (CmmStore curCCSAddr
152 (CmmLoad (cmmOffset (CmmReg tso) tso_CCCS) wordRep))
154 emitOpenNursery = stmtsC [
155 -- Hp = CurrentNursery->free - 1;
156 CmmAssign hp (cmmOffsetW (CmmLoad nursery_bdescr_free wordRep) (-1)),
158 -- HpLim = CurrentNursery->start +
159 -- CurrentNursery->blocks*BLOCK_SIZE_W - 1;
162 (CmmLoad nursery_bdescr_start wordRep)
164 (CmmMachOp mo_wordMul [
165 CmmMachOp (MO_S_Conv I32 wordRep)
166 [CmmLoad nursery_bdescr_blocks I32],
167 CmmLit (mkIntCLit bLOCK_SIZE)
175 nursery_bdescr_free = cmmOffset stgCurrentNursery oFFSET_bdescr_free
176 nursery_bdescr_start = cmmOffset stgCurrentNursery oFFSET_bdescr_start
177 nursery_bdescr_blocks = cmmOffset stgCurrentNursery oFFSET_bdescr_blocks
179 tso_SP = tsoFieldB oFFSET_StgTSO_sp
180 tso_STACK = tsoFieldB oFFSET_StgTSO_stack
181 tso_CCCS = tsoProfFieldB oFFSET_StgTSO_CCCS
183 -- The TSO struct has a variable header, and an optional StgTSOProfInfo in
184 -- the middle. The fields we're interested in are after the StgTSOProfInfo.
185 tsoFieldB :: ByteOff -> ByteOff
187 | opt_SccProfilingOn = off + sIZEOF_StgTSOProfInfo + fixedHdrSize * wORD_SIZE
188 | otherwise = off + fixedHdrSize * wORD_SIZE
190 tsoProfFieldB :: ByteOff -> ByteOff
191 tsoProfFieldB off = off + fixedHdrSize * wORD_SIZE
195 stgCurrentTSO = CmmReg currentTSO
196 stgCurrentNursery = CmmReg currentNursery
199 spLim = CmmGlobal SpLim
201 hpLim = CmmGlobal HpLim
202 currentTSO = CmmGlobal CurrentTSO
203 currentNursery = CmmGlobal CurrentNursery
205 -- -----------------------------------------------------------------------------
206 -- For certain types passed to foreign calls, we adjust the actual
207 -- value passed to the call. Two main cases: for ForeignObj# we pass
208 -- the pointer inside the ForeignObj# closure, and for ByteArray#/Array# we
209 -- pass the address of the actual array, not the address of the heap object.
211 shimForeignCallArg :: StgArg -> CmmExpr -> CmmExpr
212 shimForeignCallArg arg expr
213 | tycon == foreignObjPrimTyCon
214 = cmmLoadIndexW expr fixedHdrSize
216 | tycon == arrayPrimTyCon || tycon == mutableArrayPrimTyCon
217 = cmmOffsetB expr arrPtrsHdrSize
219 | tycon == byteArrayPrimTyCon || tycon == mutableByteArrayPrimTyCon
220 = cmmOffsetB expr arrWordsHdrSize
224 -- should be a tycon app, since this is a foreign call
225 tycon = tyConAppTyCon (repType (stgArgType arg))