diff --git a/compiler/cmm/Cmm.hs b/compiler/cmm/Cmm.hs
index 383ed060e08b85b9cd48df7dc3e4700978374c2d..4b18e46cdf010196affb3d0a0c3d26fa924657f2 100644
--- a/compiler/cmm/Cmm.hs
+++ b/compiler/cmm/Cmm.hs
@@ -174,7 +174,9 @@ data ClosureTypeInfo
   | ThunkInfo  ClosureLayout C_SRT
   | ThunkSelectorInfo SelectorOffset C_SRT
   | ContInfo
-      [Maybe LocalReg]  -- stack layout
+      [Maybe LocalReg]  -- Stack layout: Just x, an item x
+                        --               Nothing: a 1-word gap
+			-- Start of list is the *young* end
       C_SRT
 
 data CmmReturnInfo = CmmMayReturn
diff --git a/compiler/cmm/CmmExpr.hs b/compiler/cmm/CmmExpr.hs
index d09be34b6a943ad261435ad786cfe5b67ac37c00..e1a78a707e3f026a0a34a861cbc346520c966a8c 100644
--- a/compiler/cmm/CmmExpr.hs
+++ b/compiler/cmm/CmmExpr.hs
@@ -95,10 +95,26 @@ data Area
   deriving (Eq, Ord)
 
 data AreaId
-  = Old -- entry parameters, jumps, and returns share one call area at old end of stack
+  = Old            -- See Note [Old Area]
   | Young BlockId
   deriving (Eq, Ord)
 
+{- Note [Old Area] 
+~~~~~~~~~~~~~~~~~~
+There is a single call area 'Old', allocated at the extreme old
+end of the stack frame (ie just younger than the return address)
+which holds:
+  * incoming (overflow) parameters, 
+  * outgoing (overflow) parameter to tail calls,
+  * outgoing (overflow) result values 
+  * the update frame (if any)
+
+Its size is the max of all these requirements.  On entry, the stack
+pointer will point to the youngest incoming parameter, which is not
+necessarily at the young end of the Old area.
+
+End of note -}
+
 type SubArea    = (Area, Int, Int) -- area, offset, width
 type SubAreaSet = FiniteMap Area [SubArea]
 type AreaMap    = FiniteMap Area Int
diff --git a/compiler/cmm/ZipCfgCmmRep.hs b/compiler/cmm/ZipCfgCmmRep.hs
index d5496a7ff862dc77683ec036614cf0c5bf9948ec..27191f38c9844b336893f3ae48278a1dacdafc1a 100644
--- a/compiler/cmm/ZipCfgCmmRep.hs
+++ b/compiler/cmm/ZipCfgCmmRep.hs
@@ -85,18 +85,31 @@ data Last
         --      one  -> second block etc
         -- Undefined outside range, and when there's a Nothing
   | LastCall {                   -- A call (native or safe foreign)
-        cml_target  :: CmmExpr,  -- never a CmmPrim to a CallishMachOp!
-        cml_cont    :: Maybe BlockId,
+        cml_target :: CmmExpr,  -- never a CmmPrim to a CallishMachOp!
+
+        cml_cont :: Maybe BlockId,
             -- BlockId of continuation (Nothing for return or tail call)
-        cml_args    :: ByteOff,  -- byte offset for youngest outgoing arg
-                                 -- (includes update frame, which must be younger)
-        cml_ret_args:: ByteOff,  -- byte offset for youngest incoming arg
-        cml_ret_off :: Maybe UpdFrameOffset}
-          -- stack offset for return (update frames);
+
+        cml_args :: ByteOff, 
+ 	    -- Byte offset, from the *old* end of the Area associated with
+            -- the BlockId (if cml_cont = Nothing, then Old area), of
+            -- youngest outgoing arg.  Set the stack pointer to this before
+	    -- transferring control.
+  	    -- (NB: an update frame might also have been stored in the Old
+	    --      area, but it'll be in an older part than the args.)
+
+        cml_ret_args :: ByteOff,  
+	    -- For calls *only*, the byte offset for youngest returned value
+	    -- This is really needed at the *return* point rather than here
+	    -- at the call, but in practice it's convenient to record it here.
+
+        cml_ret_off :: Maybe UpdFrameOffset
+          -- Stack offset for return (update frames);
           -- The return offset should be Nothing only if we have to create
           -- a new call, e.g. for a procpoint, in which case it's an invariant
           -- that the call does not stand for a return or a tail call,
           -- and the successor does not need an info table.
+	}
 
 data MidCallTarget	-- The target of a MidUnsafeCall
   = ForeignTarget 	-- A foreign procedure