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

Reply via email to