--
-- 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 Constants
-import StaticFlags ( opt_SccProfilingOn )
+import StaticFlags
import Outputable
-import Monad ( when )
+import MachRegs (callerSaveVolatileRegs)
+ -- HACK: this is part of the NCG so we shouldn't use this, but we need
+ -- it for now to eliminate the need for saved regs to be in CmmCall.
+ -- The long term solution is to factor callerSaveVolatileRegs
+ -- from nativeGen into codeGen
+
+import Control.Monad
-- -----------------------------------------------------------------------------
-- Code generation for Foreign Calls
emitForeignCall' safety results target args vols
| 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)
+ stmtsC caller_load
| otherwise = do
id <- newTemp wordRep
temp_args <- load_args_into_temps args
+ temp_target <- load_target_into_temp target
+ let (caller_save, caller_load) = callerSaveVolatileRegs vols
emitSaveThreadState
+ stmtsC caller_save
stmtC (CmmCall (CmmForeignCall suspendThread CCallConv)
[(id,PtrHint)]
[ (CmmReg (CmmGlobal BaseReg), PtrHint) ]
- vols
)
- stmtC (CmmCall target results temp_args vols)
+ stmtC (CmmCall temp_target results temp_args)
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_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 (e,hint) = do
+ tmp <- maybe_assign_temp e
+ return (tmp,hint)
-maybe_assignTemp (e, hint)
- | hasNoGlobalRegs e = return (e, hint)
+load_target_into_temp (CmmForeignCall expr conv) = do
+ tmp <- maybe_assign_temp expr
+ return (CmmForeignCall tmp conv)
+load_target_info_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)
+ return (CmmReg reg)
-- -----------------------------------------------------------------------------
-- Save/restore the thread state in the TSO