1 -----------------------------------------------------------------------------
3 -- Code generation for foreign calls.
5 -- (c) The University of Glasgow 2004-2006
7 -----------------------------------------------------------------------------
14 emitSaveThreadState, -- will be needed by the Cmm parser
15 emitLoadThreadState, -- ditto
20 #include "HsVersions.h"
41 -- -----------------------------------------------------------------------------
42 -- Code generation for Foreign Calls
45 :: [(CmmReg,MachHint)] -- where to put the results
46 -> ForeignCall -- the op
47 -> [StgArg] -- arguments
48 -> StgLiveVars -- live vars, in case we need to save them
50 cgForeignCall results fcall stg_args live
52 reps_n_amodes <- getArgAmodes stg_args
54 -- Get the *non-void* args, and jiggle them with shimForeignCall
55 arg_exprs = [ shimForeignCallArg stg_arg expr
56 | (stg_arg, (rep,expr)) <- stg_args `zip` reps_n_amodes,
59 arg_hints = zip arg_exprs (map (typeHint.stgArgType) stg_args)
61 emitForeignCall results fcall arg_hints live
65 :: [(CmmReg,MachHint)] -- where to put the results
66 -> ForeignCall -- the op
67 -> [(CmmExpr,MachHint)] -- arguments
68 -> StgLiveVars -- live vars, in case we need to save them
71 emitForeignCall results (CCall (CCallSpec target cconv safety)) args live
72 = do vols <- getVolatileRegs live
73 emitForeignCall' safety results
74 (CmmForeignCall cmm_target cconv) call_args (Just vols)
76 (call_args, cmm_target)
78 StaticTarget lbl -> (args, CmmLit (CmmLabel
79 (mkForeignLabel lbl call_size False)))
80 DynamicTarget -> case args of (fn,_):rest -> (rest, fn)
82 -- in the stdcall calling convention, the symbol needs @size appended
83 -- to it, where size is the total number of bytes of arguments. We
84 -- attach this info to the CLabel here, and the CLabel pretty printer
85 -- will generate the suffix when the label is printed.
87 | StdCallConv <- cconv = Just (sum (map (arg_size.cmmExprRep.fst) args))
90 -- ToDo: this might not be correct for 64-bit API
91 arg_size rep = max (machRepByteWidth rep) wORD_SIZE
93 emitForeignCall results (DNCall _) args live
94 = panic "emitForeignCall: DNCall"
97 -- alternative entry point, used by CmmParse
100 -> [(CmmReg,MachHint)] -- where to put the results
101 -> CmmCallTarget -- the op
102 -> [(CmmExpr,MachHint)] -- arguments
103 -> Maybe [GlobalReg] -- live vars, in case we need to save them
105 emitForeignCall' safety results target args vols
106 | not (playSafe safety) = do
107 temp_args <- load_args_into_temps args
108 stmtC (CmmCall target results temp_args vols)
111 id <- newTemp wordRep
112 temp_args <- load_args_into_temps args
113 temp_target <- load_target_into_temp target
115 stmtC (CmmCall (CmmForeignCall suspendThread CCallConv)
117 [ (CmmReg (CmmGlobal BaseReg), PtrHint) ]
120 stmtC (CmmCall temp_target results temp_args vols)
121 stmtC (CmmCall (CmmForeignCall resumeThread CCallConv)
122 [ (CmmGlobal BaseReg, PtrHint) ]
123 -- Assign the result to BaseReg: we
124 -- might now have a different
126 [ (CmmReg id, PtrHint) ]
132 suspendThread = CmmLit (CmmLabel (mkRtsCodeLabel SLIT("suspendThread")))
133 resumeThread = CmmLit (CmmLabel (mkRtsCodeLabel SLIT("resumeThread")))
136 -- we might need to load arguments into temporaries before
137 -- making the call, because certain global registers might
138 -- overlap with registers that the C calling convention uses
139 -- for passing arguments.
141 -- This is a HACK; really it should be done in the back end, but
142 -- it's easier to generate the temporaries here.
143 load_args_into_temps = mapM arg_assign_temp
144 where arg_assign_temp (e,hint) = do
145 tmp <- maybe_assign_temp e
148 load_target_into_temp (CmmForeignCall expr conv) = do
149 tmp <- maybe_assign_temp expr
150 return (CmmForeignCall tmp conv)
151 load_target_info_temp other_target =
155 | hasNoGlobalRegs e = return e
157 -- don't use assignTemp, it uses its own notion of "trivial"
158 -- expressions, which are wrong here
159 reg <- newTemp (cmmExprRep e)
160 stmtC (CmmAssign reg e)
163 -- -----------------------------------------------------------------------------
164 -- Save/restore the thread state in the TSO
166 -- This stuff can't be done in suspendThread/resumeThread, because it
167 -- refers to global registers which aren't available in the C world.
169 emitSaveThreadState = do
170 -- CurrentTSO->sp = Sp;
171 stmtC $ CmmStore (cmmOffset stgCurrentTSO tso_SP) stgSp
173 -- and save the current cost centre stack in the TSO when profiling:
174 when opt_SccProfilingOn $
175 stmtC (CmmStore (cmmOffset stgCurrentTSO tso_CCCS) curCCS)
177 -- CurrentNursery->free = Hp+1;
178 emitCloseNursery = stmtC $ CmmStore nursery_bdescr_free (cmmOffsetW stgHp 1)
180 emitLoadThreadState = do
181 tso <- newTemp wordRep
184 CmmAssign tso stgCurrentTSO,
186 CmmAssign sp (CmmLoad (cmmOffset (CmmReg tso) tso_SP)
188 -- SpLim = tso->stack + RESERVED_STACK_WORDS;
189 CmmAssign spLim (cmmOffsetW (cmmOffset (CmmReg tso) tso_STACK)
190 rESERVED_STACK_WORDS)
193 -- and load the current cost centre stack from the TSO when profiling:
194 when opt_SccProfilingOn $
195 stmtC (CmmStore curCCSAddr
196 (CmmLoad (cmmOffset (CmmReg tso) tso_CCCS) wordRep))
198 emitOpenNursery = stmtsC [
199 -- Hp = CurrentNursery->free - 1;
200 CmmAssign hp (cmmOffsetW (CmmLoad nursery_bdescr_free wordRep) (-1)),
202 -- HpLim = CurrentNursery->start +
203 -- CurrentNursery->blocks*BLOCK_SIZE_W - 1;
206 (CmmLoad nursery_bdescr_start wordRep)
208 (CmmMachOp mo_wordMul [
209 CmmMachOp (MO_S_Conv I32 wordRep)
210 [CmmLoad nursery_bdescr_blocks I32],
211 CmmLit (mkIntCLit bLOCK_SIZE)
219 nursery_bdescr_free = cmmOffset stgCurrentNursery oFFSET_bdescr_free
220 nursery_bdescr_start = cmmOffset stgCurrentNursery oFFSET_bdescr_start
221 nursery_bdescr_blocks = cmmOffset stgCurrentNursery oFFSET_bdescr_blocks
223 tso_SP = tsoFieldB oFFSET_StgTSO_sp
224 tso_STACK = tsoFieldB oFFSET_StgTSO_stack
225 tso_CCCS = tsoProfFieldB oFFSET_StgTSO_CCCS
227 -- The TSO struct has a variable header, and an optional StgTSOProfInfo in
228 -- the middle. The fields we're interested in are after the StgTSOProfInfo.
229 tsoFieldB :: ByteOff -> ByteOff
231 | opt_SccProfilingOn = off + sIZEOF_StgTSOProfInfo + fixedHdrSize * wORD_SIZE
232 | otherwise = off + fixedHdrSize * wORD_SIZE
234 tsoProfFieldB :: ByteOff -> ByteOff
235 tsoProfFieldB off = off + fixedHdrSize * wORD_SIZE
239 stgCurrentTSO = CmmReg currentTSO
240 stgCurrentNursery = CmmReg currentNursery
243 spLim = CmmGlobal SpLim
245 hpLim = CmmGlobal HpLim
246 currentTSO = CmmGlobal CurrentTSO
247 currentNursery = CmmGlobal CurrentNursery
249 -- -----------------------------------------------------------------------------
250 -- For certain types passed to foreign calls, we adjust the actual
251 -- value passed to the call. For ByteArray#/Array# we pass the
252 -- address of the actual array, not the address of the heap object.
254 shimForeignCallArg :: StgArg -> CmmExpr -> CmmExpr
255 shimForeignCallArg arg expr
256 | tycon == arrayPrimTyCon || tycon == mutableArrayPrimTyCon
257 = cmmOffsetB expr arrPtrsHdrSize
259 | tycon == byteArrayPrimTyCon || tycon == mutableByteArrayPrimTyCon
260 = cmmOffsetB expr arrWordsHdrSize
264 -- should be a tycon app, since this is a foreign call
265 tycon = tyConAppTyCon (repType (stgArgType arg))