Repository : ssh://darcs.haskell.org//srv/darcs/ghc On branch : master
http://hackage.haskell.org/trac/ghc/changeset/22d5822929be3591d8a16b23a02f97e196ac2c09 >--------------------------------------------------------------- commit 22d5822929be3591d8a16b23a02f97e196ac2c09 Author: Simon Marlow <[email protected]> Date: Fri Aug 3 11:23:44 2012 +0100 Foreign calls may clobber caller-saves registers See Note [foreign calls clobber GlobalRegs] >--------------------------------------------------------------- compiler/cmm/CmmNode.hs | 36 ++++++++++++++++++++++++++++-------- compiler/cmm/CmmSink.hs | 25 +++++++++++++++++++++---- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/compiler/cmm/CmmNode.hs b/compiler/cmm/CmmNode.hs index 702e2eb..fa41ed5 100644 --- a/compiler/cmm/CmmNode.hs +++ b/compiler/cmm/CmmNode.hs @@ -51,10 +51,11 @@ data CmmNode e x where [CmmFormal] -> -- zero or more results [CmmActual] -> -- zero or more arguments CmmNode O O - -- Semantics: kills only result regs; all other regs (both GlobalReg - -- and LocalReg) are preserved. But there is a current - -- bug for what can be put in arguments, see - -- Note [Register Parameter Passing] + -- Semantics: clobbers any GlobalRegs for which callerSaves r == True + -- See Note [foreign calls clobber GlobalRegs] + -- + -- Also, there is a current bug for what can be put in + -- arguments, see Note [Register Parameter Passing] CmmBranch :: ULabel -> CmmNode O C -- Goto another block in the same procedure @@ -147,12 +148,31 @@ ultimately expands to pop "return address" We cannot "lower" a safe foreign call to this sequence of Cmms, because after we've saved Sp all the Cmm optimiser's assumptions are broken. -Furthermore, currently the smart Cmm constructors know the calling -conventions for Haskell, the garbage collector, etc, and "lower" them -so that a LastCall passes no parameters or results. But the smart -constructors do *not* (currently) know the foreign call conventions. Note that a safe foreign call needs an info table. + +So Safe Foreign Calls must remain as last nodes until the stack is +made manifest in CmmLayoutStack, where they are lowered into the above +sequence. +-} + +{- Note [foreign calls clobber GlobalRegs] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A foreign call is defined to clobber any GlobalRegs that are mapped to +caller-saves machine registers (according to the prevailing C ABI). +StgCmmUtils.callerSaves tells you which GlobalRegs are caller-saves. + +This is a design choice that makes it easier to generate code later. +We could instead choose to say that foreign calls do *not* clobber +caller-saves regs, but then we would have to figure out which regs +were live across the call later and insert some saves/restores. + +Furthermore when we generate code we never have any GlobalRegs live +across a call, because they are always copied-in to LocalRegs and +copied-out again before making a call/jump. So all we have to do is +avoid any code motion that would make a caller-saves GlobalReg live +across a foreign call during subsequent optimisations. -} {- Note [Register parameter passing] diff --git a/compiler/cmm/CmmSink.hs b/compiler/cmm/CmmSink.hs index 2a9ecd3..9a5f7e7 100644 --- a/compiler/cmm/CmmSink.hs +++ b/compiler/cmm/CmmSink.hs @@ -3,6 +3,8 @@ module CmmSink ( cmmSink ) where +import StgCmmUtils (callerSaves) + import Cmm import BlockId import CmmLive @@ -347,14 +349,29 @@ conflicts :: Assignment -> CmmNode O x -> Bool | CmmStore addr' e <- node, memConflicts addr (loadAddr addr' (cmmExprWidth e)) = True -- (3) an assignment to Hp/Sp conflicts with a heap/stack read respectively - | HeapMem <- addr, CmmAssign (CmmGlobal Hp) _ <- node = True - | StackMem <- addr, CmmAssign (CmmGlobal Sp) _ <- node = True - | SpMem{} <- addr, CmmAssign (CmmGlobal Sp) _ <- node = True + | HeapMem <- addr, CmmAssign (CmmGlobal Hp) _ <- node = True + | StackMem <- addr, CmmAssign (CmmGlobal Sp) _ <- node = True + | SpMem{} <- addr, CmmAssign (CmmGlobal Sp) _ <- node = True + + -- (4) assignments that read caller-saves GlobalRegs conflict with a + -- foreign call. See Note [foreign calls clobber GlobalRegs]. + | CmmUnsafeForeignCall{} <- node, anyCallerSavesRegs rhs = True + + -- (5) foreign calls clobber memory, but not heap/stack memory + | CmmUnsafeForeignCall{} <- node, AnyMem <- addr = True - -- (4) otherwise, no conflict + -- (6) native calls clobber any memory + | CmmCall{} <- node, memConflicts addr AnyMem = True + + -- (7) otherwise, no conflict | otherwise = False +anyCallerSavesRegs :: CmmExpr -> Bool +anyCallerSavesRegs e = wrapRecExpf f e False + where f (CmmReg (CmmGlobal r)) _ | callerSaves r = True + f _ z = z + -- An abstraction of memory read or written. data AbsMem = NoMem -- no memory accessed _______________________________________________ Cvs-ghc mailing list [email protected] http://www.haskell.org/mailman/listinfo/cvs-ghc
