X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=compiler%2Fcmm%2FPprC.hs;h=ceadebe8e727df5f2046f94f6b8d94769349ea38;hb=0c6b69eada9cb7a6302f98f4de70cc71d3544c44;hp=a8d30668b7e39d55b953d31620b6d04044db18e1;hpb=0065d5ab628975892cea1ec7303f968c3338cbe1;p=ghc-hetmet.git diff --git a/compiler/cmm/PprC.hs b/compiler/cmm/PprC.hs index a8d3066..ceadebe 100644 --- a/compiler/cmm/PprC.hs +++ b/compiler/cmm/PprC.hs @@ -1,8 +1,15 @@ +{-# OPTIONS -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/Commentary/CodingStyle#Warnings +-- for details + ----------------------------------------------------------------------------- -- -- Pretty-printing of Cmm as C, suitable for feeding gcc -- --- (c) The University of Glasgow 2004 +-- (c) The University of Glasgow 2004-2006 -- ----------------------------------------------------------------------------- @@ -28,40 +35,40 @@ 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 ) - -#ifdef DEBUG -import PprCmm () -- instances only --- import Debug.Trace -#endif +import Data.List +import Data.Bits +import Data.Char +import System.IO +import Data.Word -#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 +76,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,14 +86,14 @@ 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 (CmmProc info clbl _params blocks) = +pprTop :: RawCmmTop -> SDoc +pprTop (CmmProc info clbl _params (ListGraph blocks)) = (if not (null info) then pprDataExterns info $$ pprWordArray (entryLblToInfoLbl clbl) info @@ -133,7 +140,6 @@ pprTop top@(CmmData _section (CmmDataLabel lbl : lits)) = -- these shouldn't appear? pprTop (CmmData _ _) = panic "PprC.pprTop: can't handle this data" - -- -------------------------------------------------------------------------- -- BasicBlocks are self-contained entities: they always end in a jump. -- @@ -194,15 +200,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 +221,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 +231,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 -> CmmFormals -> CmmActuals -> SDoc pprCFunType cconv ress args = hcat [ res_type ress, @@ -234,9 +240,9 @@ pprCFunType cconv ress args ] where res_type [] = ptext SLIT("void") - res_type [(one,hint)] = machRepHintCType (cmmRegRep one) hint + res_type [CmmHinted one hint] = machRepHintCType (localRegRep one) hint - arg_type (expr,hint) = machRepHintCType (cmmExprRep expr) hint + arg_type (CmmHinted expr hint) = machRepHintCType (cmmExprRep expr) hint -- --------------------------------------------------------------------- -- unconditional branches @@ -317,13 +323,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 +361,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 @@ -399,7 +420,13 @@ pprLit1 other = pprLit other pprStatics :: [CmmStatic] -> [SDoc] pprStatics [] = [] pprStatics (CmmStaticLit (CmmFloat f F32) : rest) + -- floats are padded to a word, see #1852 + | wORD_SIZE == 8, CmmStaticLit (CmmInt 0 I32) : rest' <- rest + = pprLit1 (floatToWord f) : pprStatics rest' + | wORD_SIZE == 4 = pprLit1 (floatToWord f) : pprStatics rest + | otherwise + = pprPanic "pprStatics: float" (vcat (map (\(CmmStaticLit l) -> ppr (cmmLitRep l)) rest)) pprStatics (CmmStaticLit (CmmFloat f F64) : rest) = map pprLit1 (doubleToWords f) ++ pprStatics rest pprStatics (CmmStaticLit (CmmInt i I64) : rest) @@ -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) @@ -547,6 +577,7 @@ pprCallishMachOp_for_C mop MO_F32_Log -> ptext SLIT("logf") MO_F32_Exp -> ptext SLIT("expf") MO_F32_Sqrt -> ptext SLIT("sqrtf") + MO_WriteBarrier -> ptext SLIT("write_barrier") -- --------------------------------------------------------------------- -- Useful #defines @@ -592,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) @@ -612,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 @@ -626,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. @@ -651,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_ *")) @@ -688,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 -> CmmFormals -> 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 @@ -714,45 +747,26 @@ 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 + ppr_assign [CmmHinted one hint] rhs + = pprLocalReg one <> ptext SLIT(" = ") + <> pprUnHint hint (localRegRep one) <> rhs ppr_assign _other _rhs = panic "pprCall: multiple results" - pprArg (expr, PtrHint) + pprArg (CmmHinted expr PtrHint) = cCast (ptext SLIT("void *")) expr -- see comment by machRepHintCType below - pprArg (expr, SignedHint) + pprArg (CmmHinted expr SignedHint) = cCast (machRepSignedCType (cmmExprRep expr)) expr - pprArg (expr, _other) + pprArg (CmmHinted expr _other) = pprExpr expr pprUnHint PtrHint rep = parens (machRepCType rep) 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 @@ -769,7 +783,7 @@ is_cish StdCallConv = True -- pprTempAndExternDecls :: [CmmBasicBlock] -> (SDoc{-temps-}, SDoc{-externs-}) pprTempAndExternDecls stmts - = (vcat (map pprTempDecl (eltsUFM temps)), + = (vcat (map pprTempDecl (uniqSetToList temps)), vcat (map (pprExternDecl False{-ToDo-}) (keysFM lbls))) where (temps, lbls) = runTE (mapM_ te_BB stmts) @@ -779,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 @@ -788,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_") @@ -834,8 +844,8 @@ 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 >> - mapM_ (te_Expr.fst) es +te_Stmt (CmmCall _ rs es _ _) = mapM_ (te_temp.hintlessCmm) rs >> + mapM_ (te_Expr.hintlessCmm) es te_Stmt (CmmCondBranch e _) = te_Expr e te_Stmt (CmmSwitch e _) = te_Expr e te_Stmt (CmmJump e _) = te_Expr e @@ -859,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. @@ -926,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) ) @@ -973,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 ] )