Add {-# OPTIONS_GHC -w #-} and some blurb to all compiler modules
[ghc-hetmet.git] / compiler / cmm / PprC.hs
index 5c60b8a..7127be3 100644 (file)
@@ -2,7 +2,7 @@
 --
 -- Pretty-printing of Cmm as C, suitable for feeding gcc
 --
--- (c) The University of Glasgow 2004
+-- (c) The University of Glasgow 2004-2006
 --
 -----------------------------------------------------------------------------
 
 
 -- ToDo: save/restore volatile registers around calls.
 
+{-# OPTIONS_GHC -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/WorkingConventions#Warnings
+-- for details
+
 module PprC (
         writeCs,
         pprStringInCStyle 
@@ -28,40 +35,45 @@ import Cmm
 import CLabel
 import MachOp
 import ForeignCall
+import ClosureInfo
 
 -- Utils
-import DynFlags                ( DynFlags, DynFlag(..), dopt )
-import Unique           ( getUnique )
+import DynFlags
+import Unique
 import UniqSet
 import FiniteMap
-import UniqFM          ( eltsUFM )
+import UniqFM
 import FastString
 import Outputable
 import Constants
-import StaticFlags     ( opt_Unregisterised )
 
 -- The rest
-import Data.List        ( intersperse, groupBy )
-import Data.Bits        ( shiftR )
-import Char             ( ord, chr )
-import IO               ( Handle )
-import DATA_BITS
-import Data.Word       ( Word8 )
+import Data.List
+import Data.Bits
+import Data.Char
+import System.IO
+import Data.Word
 
 #ifdef DEBUG
 import PprCmm          () -- instances only
 -- import Debug.Trace
 #endif
 
-#if __GLASGOW_HASKELL__ >= 504
 import Data.Array.ST
+import Control.Monad.ST
+
+#if x86_64_TARGET_ARCH
+import StaticFlags     ( opt_Unregisterised )
+#endif
+
+#if defined(alpha_TARGET_ARCH) || defined(mips_TARGET_ARCH) || defined(mipsel_TARGET_ARCH) || defined(arm_TARGET_ARCH)
+#define BEWARE_LOAD_STORE_ALIGNMENT
 #endif
-import MONAD_ST
 
 -- --------------------------------------------------------------------------
 -- Top level
 
-pprCs :: DynFlags -> [Cmm] -> SDoc
+pprCs :: DynFlags -> [RawCmm] -> SDoc
 pprCs dflags cmms
  = pprCode CStyle (vcat $ map (\c -> split_marker $$ pprC c) cmms)
  where
@@ -69,7 +81,7 @@ pprCs dflags cmms
      | dopt Opt_SplitObjs dflags = ptext SLIT("__STG_SPLIT_MARKER")
      | otherwise                = empty
 
-writeCs :: DynFlags -> Handle -> [Cmm] -> IO ()
+writeCs :: DynFlags -> Handle -> [RawCmm] -> IO ()
 writeCs dflags handle cmms 
   = printForC handle (pprCs dflags cmms)
 
@@ -79,13 +91,13 @@ writeCs dflags handle cmms
 -- for fun, we could call cmmToCmm over the tops...
 --
 
-pprC :: Cmm -> SDoc
+pprC :: RawCmm -> SDoc
 pprC (Cmm tops) = vcat $ intersperse (text "") $ map pprTop tops
 
 --
 -- top level procs
 -- 
-pprTop :: CmmTop -> SDoc
+pprTop :: RawCmmTop -> SDoc
 pprTop (CmmProc info clbl _params blocks) =
     (if not (null info)
         then pprDataExterns info $$
@@ -194,15 +206,15 @@ pprStmt stmt = case stmt of
        where
          rep = cmmExprRep src
 
-    CmmCall (CmmForeignCall fn cconv) results args volatile -> 
+    CmmCall (CmmCallee fn cconv) results args safety _ret ->
        -- Controversial: leave this out for now.
        -- pprUndef fn $$
 
-       pprCall ppr_fn cconv results args volatile
+       pprCall ppr_fn cconv results args safety
        where
        ppr_fn = case fn of
                   CmmLit (CmmLabel lbl) -> pprCLabel lbl
-                  _other -> parens (cCast (pprCFunType cconv results args) fn)
+                  _ -> parens (cCast (pprCFunType cconv results args) fn)
                        -- for a dynamic call, cast the expression to
                        -- a function of the right type (we hope).
 
@@ -215,8 +227,8 @@ pprStmt stmt = case stmt of
           ptext SLIT("#undef") <+> pprCLabel lbl
        pprUndef _ = empty
 
-    CmmCall (CmmPrim op) results args volatile -> 
-       pprCall ppr_fn CCallConv results args volatile
+    CmmCall (CmmPrim op) results args safety _ret ->
+       pprCall ppr_fn CCallConv results args safety
        where
        ppr_fn = pprCallishMachOp_for_C op
 
@@ -225,7 +237,7 @@ pprStmt stmt = case stmt of
     CmmJump lbl _params      -> mkJMP_(pprExpr lbl) <> semi
     CmmSwitch arg ids        -> pprSwitch arg ids
 
-pprCFunType :: CCallConv -> [(CmmReg,MachHint)] -> [(CmmExpr,MachHint)] -> SDoc
+pprCFunType :: CCallConv -> CmmHintFormals -> CmmActuals -> SDoc
 pprCFunType cconv ress args
   = hcat [
        res_type ress,
@@ -234,7 +246,7 @@ pprCFunType cconv ress args
    ]
   where
        res_type [] = ptext SLIT("void")
-       res_type [(one,hint)] = machRepHintCType (cmmRegRep one) hint
+       res_type [(one,hint)] = machRepHintCType (localRegRep one) hint
 
        arg_type (expr,hint) = machRepHintCType (cmmExprRep expr) hint
 
@@ -317,13 +329,14 @@ pprExpr e = case e of
        -> char '*' <> pprAsPtrReg r
 
     CmmLoad (CmmRegOff r off) rep
-       | isPtrReg r && rep == wordRep 
+       | isPtrReg r && rep == wordRep && (off `rem` wORD_SIZE == 0)
        -- ToDo: check that the offset is a word multiple?
+        --       (For tagging to work, I had to avoid unaligned loads. --ARY)
        -> pprAsPtrReg r <> brackets (ppr (off `shiftR` wordShift))
 
     CmmLoad expr rep ->
        -- the general case:
-       char '*' <> parens (cCast (machRepPtrCType rep) expr)
+       cLoad expr rep
 
     CmmReg reg      -> pprCastReg reg
     CmmRegOff reg 0 -> pprCastReg reg
@@ -354,6 +367,20 @@ pprMachOpApp op args
        isMulMayOfloOp _ = False
 
 pprMachOpApp mop args
+  | Just ty <- machOpNeedsCast mop 
+  = ty <> parens (pprMachOpApp' mop args)
+  | otherwise
+  = pprMachOpApp' mop args
+
+-- Comparisons in C have type 'int', but we want type W_ (this is what
+-- resultRepOfMachOp says).  The other C operations inherit their type
+-- from their operands, so no casting is required.
+machOpNeedsCast :: MachOp -> Maybe SDoc
+machOpNeedsCast mop
+  | isComparisonMachOp mop = Just mkW_
+  | otherwise              = Nothing
+
+pprMachOpApp' mop args
  = case args of
     -- dyadic
     [x,y] -> pprArg x <+> pprMachOp_for_C mop <+> pprArg y
@@ -413,6 +440,9 @@ pprStatics (CmmStaticLit (CmmInt i I64) : rest)
 #endif
   where r = i .&. 0xffffffff
        q = i `shiftR` 32
+pprStatics (CmmStaticLit (CmmInt i rep) : rest)
+  | machRepByteWidth rep /= wORD_SIZE
+  = panic "pprStatics: cannot emit a non-word-sized static literal"
 pprStatics (CmmStaticLit lit : rest)
   = pprLit1 lit : pprStatics rest
 pprStatics (other : rest)
@@ -593,18 +623,15 @@ pprAssign :: CmmReg -> CmmExpr -> SDoc
 
 -- dest is a reg, rhs is a reg
 pprAssign r1 (CmmReg r2)
-   | not (isStrangeTypeReg r1) && not (isStrangeTypeReg r2)
-   || isPtrReg r1 && isPtrReg r2
+   | isPtrReg r1 && isPtrReg r2
    = hcat [ pprAsPtrReg r1, equals, pprAsPtrReg r2, semi ]
 
 -- dest is a reg, rhs is a CmmRegOff
 pprAssign r1 (CmmRegOff r2 off)
-   | not (isStrangeTypeReg r1) && not (isStrangeTypeReg r2)
-   || isPtrReg r1 && isPtrReg r2
+   | isPtrReg r1 && isPtrReg r2 && (off `rem` wORD_SIZE == 0)
    = hcat [ pprAsPtrReg r1, equals, pprAsPtrReg r2, op, int off', semi ]
   where
-       off1 | isPtrReg r2 = off `shiftR` wordShift
-            | otherwise   = off
+       off1 = off `shiftR` wordShift
 
        (op,off') | off >= 0  = (char '+', off1)
                  | otherwise = (char '-', -off1)
@@ -613,12 +640,12 @@ pprAssign r1 (CmmRegOff r2 off)
 -- We can't cast the lvalue, so we have to cast the rhs if necessary.  Casting
 -- the lvalue elicits a warning from new GCC versions (3.4+).
 pprAssign r1 r2
-  | isPtrReg r1
-  = pprAsPtrReg r1 <> ptext SLIT(" = ") <> mkP_ <> pprExpr1 r2 <> semi
-  | Just ty <- strangeRegType r1
-  = pprReg r1 <> ptext SLIT(" = ") <> parens ty <> pprExpr1 r2 <> semi
-  | otherwise
-  = pprReg r1 <> ptext SLIT(" = ") <> pprExpr r2 <> semi
+  | isFixedPtrReg r1             = mkAssign (mkP_ <> pprExpr1 r2)
+  | Just ty <- strangeRegType r1 = mkAssign (parens ty <> pprExpr1 r2)
+  | otherwise                    = mkAssign (pprExpr r2)
+    where mkAssign x = if r1 == CmmGlobal BaseReg
+                       then ptext SLIT("ASSIGN_BaseReg") <> parens x <> semi
+                       else pprReg r1 <> ptext SLIT(" = ") <> x <> semi
 
 -- ---------------------------------------------------------------------
 -- Registers
@@ -627,20 +654,26 @@ pprCastReg reg
    | isStrangeTypeReg reg = mkW_ <> pprReg reg
    | otherwise            = pprReg reg
 
--- True if the register has type StgPtr in C, otherwise it has an
--- integer type.  We need to take care with pointer arithmetic on registers
--- with type StgPtr.
-isPtrReg :: CmmReg -> Bool
-isPtrReg (CmmLocal _) = False
-isPtrReg (CmmGlobal r) = isPtrGlobalReg r
+-- True if (pprReg reg) will give an expression with type StgPtr.  We
+-- need to take care with pointer arithmetic on registers with type
+-- StgPtr.
+isFixedPtrReg :: CmmReg -> Bool
+isFixedPtrReg (CmmLocal _) = False
+isFixedPtrReg (CmmGlobal r) = isFixedPtrGlobalReg r
 
-isPtrGlobalReg :: GlobalReg -> Bool
-isPtrGlobalReg (VanillaReg n)  = True
-isPtrGlobalReg Sp              = True
-isPtrGlobalReg Hp              = True
-isPtrGlobalReg HpLim           = True
-isPtrGlobalReg SpLim           = True
-isPtrGlobalReg _               = False
+-- True if (pprAsPtrReg reg) will give an expression with type StgPtr
+isPtrReg :: CmmReg -> Bool
+isPtrReg (CmmLocal _)              = False
+isPtrReg (CmmGlobal (VanillaReg n)) = True -- if we print via pprAsPtrReg
+isPtrReg (CmmGlobal reg)           = isFixedPtrGlobalReg reg
+
+-- True if this global reg has type StgPtr
+isFixedPtrGlobalReg :: GlobalReg -> Bool
+isFixedPtrGlobalReg Sp                 = True
+isFixedPtrGlobalReg Hp                 = True
+isFixedPtrGlobalReg HpLim      = True
+isFixedPtrGlobalReg SpLim      = True
+isFixedPtrGlobalReg _          = False
 
 -- True if in C this register doesn't have the type given by 
 -- (machRepCType (cmmRegRep reg)), so it has to be cast.
@@ -652,7 +685,7 @@ isStrangeTypeGlobal :: GlobalReg -> Bool
 isStrangeTypeGlobal CurrentTSO         = True
 isStrangeTypeGlobal CurrentNursery     = True
 isStrangeTypeGlobal BaseReg            = True
-isStrangeTypeGlobal r                  = isPtrGlobalReg r
+isStrangeTypeGlobal r                  = isFixedPtrGlobalReg r
 
 strangeRegType :: CmmReg -> Maybe SDoc
 strangeRegType (CmmGlobal CurrentTSO) = Just (ptext SLIT("struct StgTSO_ *"))
@@ -689,21 +722,20 @@ pprGlobalReg gr = case gr of
     GCFun          -> ptext SLIT("stg_gc_fun")
 
 pprLocalReg :: LocalReg -> SDoc
-pprLocalReg (LocalReg uniq _rep) = char '_' <> ppr uniq
+pprLocalReg (LocalReg uniq _ _) = char '_' <> ppr uniq
 
 -- -----------------------------------------------------------------------------
 -- Foreign Calls
 
-pprCall :: SDoc -> CCallConv -> [(CmmReg,MachHint)] -> [(CmmExpr,MachHint)]
-       -> Maybe [GlobalReg] -> SDoc
+pprCall :: SDoc -> CCallConv -> CmmHintFormals -> CmmActuals -> CmmSafety
+       -> SDoc
 
-pprCall ppr_fn cconv results args vols
+pprCall ppr_fn cconv results args _
   | not (is_cish cconv)
   = panic "pprCall: unknown calling convention"
 
   | otherwise
-  = save vols $$
-    ptext SLIT("CALLER_SAVE_SYSTEM") $$
+  =
 #if x86_64_TARGET_ARCH
        -- HACK around gcc optimisations.
        -- x86_64 needs a __DISCARD__() here, to create a barrier between
@@ -715,22 +747,12 @@ pprCall ppr_fn cconv results args vols
        then ptext SLIT("__DISCARD__();") 
        else empty) $$
 #endif
-    ppr_assign results (ppr_fn <> parens (commafy (map pprArg args))) <> semi $$
-    ptext SLIT("CALLER_RESTORE_SYSTEM") $$
-    restore vols
+    ppr_assign results (ppr_fn <> parens (commafy (map pprArg args))) <> semi
   where 
      ppr_assign []           rhs = rhs
-     ppr_assign [(reg@(CmmGlobal BaseReg), hint)] rhs
-        | Just ty <- strangeRegType reg
-        = ptext SLIT("ASSIGN_BaseReg") <> parens (parens ty <> rhs)
-        -- BaseReg is special, sometimes it isn't an lvalue and we
-        -- can't assign to it.
      ppr_assign [(one,hint)] rhs
-        | Just ty <- strangeRegType one
-        = pprReg one <> ptext SLIT(" = ") <> parens ty <> rhs
-        | otherwise
-        = pprReg one <> ptext SLIT(" = ")
-                <> pprUnHint hint (cmmRegRep one) <> rhs
+        = pprLocalReg one <> ptext SLIT(" = ")
+                <> pprUnHint hint (localRegRep one) <> rhs
      ppr_assign _other _rhs = panic "pprCall: multiple results"
 
      pprArg (expr, PtrHint)
@@ -745,15 +767,6 @@ pprCall ppr_fn cconv results args vols
      pprUnHint SignedHint rep = parens (machRepCType rep)
      pprUnHint _          _   = empty
 
-     save    = save_restore SLIT("CALLER_SAVE")
-     restore = save_restore SLIT("CALLER_RESTORE")
-
-       -- Nothing says "I don't know what's live; save everything"
-       -- CALLER_SAVE_USER is defined in ghc/includes/Regs.h
-     save_restore txt Nothing     = ptext txt <> ptext SLIT("_USER")
-     save_restore txt (Just these) = vcat (map saveRestoreGlobal these)
-       where saveRestoreGlobal r = ptext txt <> char '_' <> pprGlobalRegName r
-
 pprGlobalRegName :: GlobalReg -> SDoc
 pprGlobalRegName gr = case gr of
     VanillaReg n   -> char 'R' <> int n  -- without the .w suffix
@@ -780,7 +793,7 @@ pprDataExterns statics
   where (_, lbls) = runTE (mapM_ te_Static statics)
 
 pprTempDecl :: LocalReg -> SDoc
-pprTempDecl l@(LocalReg _uniq rep)
+pprTempDecl l@(LocalReg _ rep _)
   = hcat [ machRepCType rep, space, pprLocalReg l, semi ]
 
 pprExternDecl :: Bool -> CLabel -> SDoc
@@ -789,12 +802,8 @@ pprExternDecl in_srt lbl
   | not (needsCDecl lbl) = empty
   | otherwise              = 
        hcat [ visibility, label_type (labelType lbl), 
-              lparen, dyn_wrapper (pprCLabel lbl), text ");" ]
+              lparen, pprCLabel lbl, text ");" ]
  where
-  dyn_wrapper d
-    | in_srt && labelDynamic lbl = text "DLL_IMPORT_DATA_VAR" <> parens d
-    | otherwise                         = d
-
   label_type CodeLabel = ptext SLIT("F_")
   label_type DataLabel = ptext SLIT("I_")
 
@@ -835,7 +844,7 @@ te_Lit _ = return ()
 te_Stmt :: CmmStmt -> TE ()
 te_Stmt (CmmAssign r e)                = te_Reg r >> te_Expr e
 te_Stmt (CmmStore l r)         = te_Expr l >> te_Expr r
-te_Stmt (CmmCall _ rs es _)    = mapM_ (te_Reg.fst) rs >>
+te_Stmt (CmmCall _ rs es _ _)  = mapM_ (te_temp.fst) rs >>
                                  mapM_ (te_Expr.fst) es
 te_Stmt (CmmCondBranch e _)    = te_Expr e
 te_Stmt (CmmSwitch e _)                = te_Expr e
@@ -860,6 +869,18 @@ te_Reg _            = return ()
 cCast :: SDoc -> CmmExpr -> SDoc
 cCast ty expr = parens ty <> pprExpr1 expr
 
+cLoad :: CmmExpr -> MachRep -> SDoc
+#ifdef BEWARE_LOAD_STORE_ALIGNMENT
+cLoad expr rep =
+    let decl = machRepCType rep <+> ptext SLIT("x") <> semi
+        struct = ptext SLIT("struct") <+> braces (decl)
+        packed_attr = ptext SLIT("__attribute__((packed))")
+        cast = parens (struct <+> packed_attr <> char '*')
+    in parens (cast <+> pprExpr1 expr) <> ptext SLIT("->x")
+#else
+cLoad expr rep = char '*' <> parens (cCast (machRepPtrCType rep) expr)
+#endif
+
 -- This is for finding the types of foreign call arguments.  For a pointer
 -- argument, we always cast the argument to (void *), to avoid warnings from
 -- the C compiler.
@@ -927,46 +948,20 @@ big_doubles
   | machRepByteWidth F64 == wORD_SIZE      = False
   | otherwise = panic "big_doubles"
 
-#if __GLASGOW_HASKELL__ >= 504
-newFloatArray :: (Int,Int) -> ST s (STUArray s Int Float)
-newFloatArray = newArray_
-
-newDoubleArray :: (Int,Int) -> ST s (STUArray s Int Double)
-newDoubleArray = newArray_
-
 castFloatToIntArray :: STUArray s Int Float -> ST s (STUArray s Int Int)
 castFloatToIntArray = castSTUArray
 
 castDoubleToIntArray :: STUArray s Int Double -> ST s (STUArray s Int Int)
 castDoubleToIntArray = castSTUArray
 
-writeFloatArray :: STUArray s Int Float -> Int -> Float -> ST s ()
-writeFloatArray = writeArray
-
-writeDoubleArray :: STUArray s Int Double -> Int -> Double -> ST s ()
-writeDoubleArray = writeArray
-
-readIntArray :: STUArray s Int Int -> Int -> ST s Int
-readIntArray = readArray
-
-#else
-
-castFloatToIntArray :: MutableByteArray s t -> ST s (MutableByteArray s t)
-castFloatToIntArray = return
-
-castDoubleToIntArray :: MutableByteArray s t -> ST s (MutableByteArray s t)
-castDoubleToIntArray = return
-
-#endif
-
 -- floats are always 1 word
 floatToWord :: Rational -> CmmLit
 floatToWord r
   = runST (do
-       arr <- newFloatArray ((0::Int),0)
-       writeFloatArray arr 0 (fromRational r)
+       arr <- newArray_ ((0::Int),0)
+       writeArray arr 0 (fromRational r)
        arr' <- castFloatToIntArray arr
-       i <- readIntArray arr' 0
+       i <- readArray arr' 0
        return (CmmInt (toInteger i) wordRep)
     )
 
@@ -974,21 +969,21 @@ doubleToWords :: Rational -> [CmmLit]
 doubleToWords r
   | big_doubles                                -- doubles are 2 words
   = runST (do
-       arr <- newDoubleArray ((0::Int),1)
-       writeDoubleArray arr 0 (fromRational r)
+       arr <- newArray_ ((0::Int),1)
+       writeArray arr 0 (fromRational r)
        arr' <- castDoubleToIntArray arr
-       i1 <- readIntArray arr' 0
-       i2 <- readIntArray arr' 1
+       i1 <- readArray arr' 0
+       i2 <- readArray arr' 1
        return [ CmmInt (toInteger i1) wordRep
               , CmmInt (toInteger i2) wordRep
               ]
     )
   | otherwise                          -- doubles are 1 word
   = runST (do
-       arr <- newDoubleArray ((0::Int),0)
-       writeDoubleArray arr 0 (fromRational r)
+       arr <- newArray_ ((0::Int),0)
+       writeArray arr 0 (fromRational r)
        arr' <- castDoubleToIntArray arr
-       i <- readIntArray arr' 0
+       i <- readArray arr' 0
        return [ CmmInt (toInteger i) wordRep ]
     )