+{-# 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/Commentary/CodingStyle#Warnings
+-- for details
+
-----------------------------------------------------------------------------
--
-- Code generation for foreign calls.
--
--- (c) The University of Glasgow 2004
+-- (c) The University of Glasgow 2004-2006
--
-----------------------------------------------------------------------------
#include "HsVersions.h"
-import StgSyn ( StgLiveVars, StgArg, stgArgType )
-import CgProf ( curCCS, curCCSAddr )
-import CgBindery ( getVolatileRegs, getArgAmodes )
+import StgSyn
+import CgProf
+import CgBindery
import CgMonad
-import CgUtils ( cmmOffsetW, cmmOffsetB, newTemp )
-import Type ( tyConAppTyCon, repType )
+import CgUtils
+import Type
import TysPrim
-import CLabel ( mkForeignLabel, mkRtsCodeLabel )
+import CLabel
import Cmm
import CmmUtils
import MachOp
import SMRep
import ForeignCall
+import ClosureInfo
import Constants
-import StaticFlags ( opt_SccProfilingOn )
+import StaticFlags
import Outputable
-import Monad ( when )
+import Control.Monad
-- -----------------------------------------------------------------------------
-- Code generation for Foreign Calls
cgForeignCall
- :: [(CmmReg,MachHint)] -- where to put the results
+ :: CmmFormals -- where to put the results
-> ForeignCall -- the op
-> [StgArg] -- arguments
-> StgLiveVars -- live vars, in case we need to save them
| (stg_arg, (rep,expr)) <- stg_args `zip` reps_n_amodes,
nonVoidArg rep]
- arg_hints = zip arg_exprs (map (typeHint.stgArgType) stg_args)
+ arg_hints = zipWith CmmHinted
+ arg_exprs (map (typeHint.stgArgType) stg_args)
-- in
emitForeignCall results fcall arg_hints live
emitForeignCall
- :: [(CmmReg,MachHint)] -- where to put the results
+ :: CmmFormals -- where to put the results
-> ForeignCall -- the op
- -> [(CmmExpr,MachHint)] -- arguments
+ -> [CmmHinted CmmExpr] -- arguments
-> StgLiveVars -- live vars, in case we need to save them
-> Code
emitForeignCall results (CCall (CCallSpec target cconv safety)) args live
= do vols <- getVolatileRegs live
+ srt <- getSRTInfo
emitForeignCall' safety results
- (CmmForeignCall cmm_target cconv) call_args (Just vols)
+ (CmmCallee cmm_target cconv) call_args (Just vols) srt CmmMayReturn
where
(call_args, cmm_target)
= case target of
StaticTarget lbl -> (args, CmmLit (CmmLabel
(mkForeignLabel lbl call_size False)))
- DynamicTarget -> case args of (fn,_):rest -> (rest, fn)
+ DynamicTarget -> case args of (CmmHinted fn _):rest -> (rest, fn)
-- in the stdcall calling convention, the symbol needs @size appended
-- to it, where size is the total number of bytes of arguments. We
-- attach this info to the CLabel here, and the CLabel pretty printer
-- will generate the suffix when the label is printed.
call_size
- | StdCallConv <- cconv = Just (sum (map (arg_size.cmmExprRep.fst) args))
+ | StdCallConv <- cconv = Just (sum (map (arg_size.cmmExprRep.hintlessCmm) args))
| otherwise = Nothing
-- ToDo: this might not be correct for 64-bit API
arg_size rep = max (machRepByteWidth rep) wORD_SIZE
-emitForeignCall results (DNCall _) args live
+emitForeignCall _ (DNCall _) _ _
= panic "emitForeignCall: DNCall"
-- alternative entry point, used by CmmParse
emitForeignCall'
:: Safety
- -> [(CmmReg,MachHint)] -- where to put the results
+ -> CmmFormals -- where to put the results
-> CmmCallTarget -- the op
- -> [(CmmExpr,MachHint)] -- arguments
+ -> [CmmHinted CmmExpr] -- arguments
-> Maybe [GlobalReg] -- live vars, in case we need to save them
+ -> C_SRT -- the SRT of the calls continuation
+ -> CmmReturnInfo
-> Code
-emitForeignCall' safety results target args vols
+emitForeignCall' safety results target args vols srt ret
| not (playSafe safety) = do
temp_args <- load_args_into_temps args
- stmtC (CmmCall target results temp_args vols)
+ let (caller_save, caller_load) = callerSaveVolatileRegs vols
+ stmtsC caller_save
+ stmtC (CmmCall target results temp_args CmmUnsafe ret)
+ stmtsC caller_load
| otherwise = do
- id <- newTemp wordRep
+ -- Both 'id' and 'new_base' are GCKindNonPtr because they're
+ -- RTS only objects and are not subject to garbage collection
+ id <- newNonPtrTemp wordRep
+ new_base <- newNonPtrTemp (cmmRegRep (CmmGlobal BaseReg))
temp_args <- load_args_into_temps args
+ temp_target <- load_target_into_temp target
+ let (caller_save, caller_load) = callerSaveVolatileRegs vols
emitSaveThreadState
- stmtC (CmmCall (CmmForeignCall suspendThread CCallConv)
- [(id,PtrHint)]
- [ (CmmReg (CmmGlobal BaseReg), PtrHint) ]
- vols
- )
- stmtC (CmmCall target results temp_args vols)
- stmtC (CmmCall (CmmForeignCall resumeThread CCallConv)
- [ (CmmGlobal BaseReg, PtrHint) ]
- -- Assign the result to BaseReg: we
- -- might now have a different
- -- Capability!
- [ (CmmReg id, PtrHint) ]
- vols
- )
+ stmtsC caller_save
+ -- The CmmUnsafe arguments are only correct because this part
+ -- of the code hasn't been moved into the CPS pass yet.
+ -- Once that happens, this function will just emit a (CmmSafe srt) call,
+ -- and the CPS will will be the one to convert that
+ -- to this sequence of three CmmUnsafe calls.
+ stmtC (CmmCall (CmmCallee suspendThread CCallConv)
+ [ CmmHinted id PtrHint ]
+ [ CmmHinted (CmmReg (CmmGlobal BaseReg)) PtrHint ]
+ CmmUnsafe ret)
+ stmtC (CmmCall temp_target results temp_args CmmUnsafe ret)
+ stmtC (CmmCall (CmmCallee resumeThread CCallConv)
+ [ CmmHinted new_base PtrHint ]
+ [ CmmHinted (CmmReg (CmmLocal id)) PtrHint ]
+ CmmUnsafe ret)
+ -- Assign the result to BaseReg: we
+ -- might now have a different Capability!
+ stmtC (CmmAssign (CmmGlobal BaseReg) (CmmReg (CmmLocal new_base)))
+ stmtsC caller_load
emitLoadThreadState
-
suspendThread = CmmLit (CmmLabel (mkRtsCodeLabel SLIT("suspendThread")))
resumeThread = CmmLit (CmmLabel (mkRtsCodeLabel SLIT("resumeThread")))
--
-- This is a HACK; really it should be done in the back end, but
-- it's easier to generate the temporaries here.
-load_args_into_temps args = mapM maybe_assignTemp args
+load_args_into_temps = mapM arg_assign_temp
+ where arg_assign_temp (CmmHinted e hint) = do
+ tmp <- maybe_assign_temp e
+ return (CmmHinted tmp hint)
-maybe_assignTemp (e, hint)
- | hasNoGlobalRegs e = return (e, hint)
+load_target_into_temp (CmmCallee expr conv) = do
+ tmp <- maybe_assign_temp expr
+ return (CmmCallee tmp conv)
+load_target_into_temp other_target =
+ return other_target
+
+maybe_assign_temp e
+ | hasNoGlobalRegs e = return e
| otherwise = do
-- don't use assignTemp, it uses its own notion of "trivial"
- -- expressions, which are wrong here
- reg <- newTemp (cmmExprRep e)
- stmtC (CmmAssign reg e)
- return (CmmReg reg, hint)
+ -- expressions, which are wrong here.
+ -- this is a NonPtr because it only duplicates an existing
+ reg <- newNonPtrTemp (cmmExprRep e) --TODO FIXME NOW
+ stmtC (CmmAssign (CmmLocal reg) e)
+ return (CmmReg (CmmLocal reg))
-- -----------------------------------------------------------------------------
-- Save/restore the thread state in the TSO
emitCloseNursery = stmtC $ CmmStore nursery_bdescr_free (cmmOffsetW stgHp 1)
emitLoadThreadState = do
- tso <- newTemp wordRep
+ tso <- newNonPtrTemp wordRep -- TODO FIXME NOW
stmtsC [
-- tso = CurrentTSO;
- CmmAssign tso stgCurrentTSO,
+ CmmAssign (CmmLocal tso) stgCurrentTSO,
-- Sp = tso->sp;
- CmmAssign sp (CmmLoad (cmmOffset (CmmReg tso) tso_SP)
+ CmmAssign sp (CmmLoad (cmmOffset (CmmReg (CmmLocal tso)) tso_SP)
wordRep),
-- SpLim = tso->stack + RESERVED_STACK_WORDS;
- CmmAssign spLim (cmmOffsetW (cmmOffset (CmmReg tso) tso_STACK)
+ CmmAssign spLim (cmmOffsetW (cmmOffset (CmmReg (CmmLocal tso)) tso_STACK)
rESERVED_STACK_WORDS)
]
emitOpenNursery
-- and load the current cost centre stack from the TSO when profiling:
when opt_SccProfilingOn $
stmtC (CmmStore curCCSAddr
- (CmmLoad (cmmOffset (CmmReg tso) tso_CCCS) wordRep))
+ (CmmLoad (cmmOffset (CmmReg (CmmLocal tso)) tso_CCCS) wordRep))
emitOpenNursery = stmtsC [
-- Hp = CurrentNursery->free - 1;