diff options
author | Simon Marlow <marlowsd@gmail.com> | 2012-11-12 11:47:51 +0000 |
---|---|---|
committer | Simon Marlow <marlowsd@gmail.com> | 2012-11-12 15:20:25 +0000 |
commit | d92bd17ffd8715f77fd49de0fed6e39c8d0ec28b (patch) | |
tree | a721be9b82241dbcce19f66defcbfa41ffefe581 /compiler/cmm/PprC.hs | |
parent | 121768dec30facc5c9ff94cf84bc9eac71e7290b (diff) | |
download | haskell-d92bd17ffd8715f77fd49de0fed6e39c8d0ec28b.tar.gz |
Remove OldCmm, convert backends to consume new Cmm
This removes the OldCmm data type and the CmmCvt pass that converts
new Cmm to OldCmm. The backends (NCGs, LLVM and C) have all been
converted to consume new Cmm.
The main difference between the two data types is that conditional
branches in new Cmm have both true/false successors, whereas in OldCmm
the false case was a fallthrough. To generate slightly better code we
occasionally need to invert a conditional to ensure that the
branch-not-taken becomes a fallthrough; this was previously done in
CmmCvt, and it is now done in CmmContFlowOpt.
We could go further and use the Hoopl Block representation for native
code, which would mean that we could use Hoopl's postorderDfs and
analyses for native code, but for now I've left it as is, using the
old ListGraph representation for native code.
Diffstat (limited to 'compiler/cmm/PprC.hs')
-rw-r--r-- | compiler/cmm/PprC.hs | 131 |
1 files changed, 69 insertions, 62 deletions
diff --git a/compiler/cmm/PprC.hs b/compiler/cmm/PprC.hs index e0ff99cb29..ee964d8701 100644 --- a/compiler/cmm/PprC.hs +++ b/compiler/cmm/PprC.hs @@ -16,6 +16,7 @@ -- ----------------------------------------------------------------------------- +{-# LANGUAGE GADTs #-} module PprC ( writeCs, pprStringInCStyle @@ -27,8 +28,10 @@ module PprC ( import BlockId import CLabel import ForeignCall -import OldCmm -import OldPprCmm () +import Cmm hiding (pprBBlock) +import PprCmm () +import Hoopl +import CmmUtils -- Utils import CPrim @@ -81,8 +84,9 @@ pprC tops = vcat $ intersperse blankLine $ map pprTop tops -- top level procs -- pprTop :: RawCmmDecl -> SDoc -pprTop proc@(CmmProc _ clbl _ (ListGraph blocks)) = - (case topInfoTable proc of +pprTop (CmmProc infos clbl _ graph) = + + (case mapLookup (g_entry graph) infos of Nothing -> empty Just (Statics info_clbl info_dat) -> pprDataExterns info_dat $$ pprWordArray info_clbl info_dat) $$ @@ -93,16 +97,12 @@ pprTop proc@(CmmProc _ clbl _ (ListGraph blocks)) = then mkFN_ else mkIF_) (ppr clbl) <+> lbrace, nest 8 temp_decls, nest 8 mkFB_, - case blocks of - [] -> empty - -- the first block doesn't get a label: - (BasicBlock _ stmts : rest) -> - nest 8 (vcat (map pprStmt stmts)) $$ - vcat (map pprBBlock rest), + vcat (map pprBBlock blocks), nest 8 mkFE_, rbrace ] ) where + blocks = toBlockList graph (temp_decls, extern_decls) = pprTempAndExternDecls blocks @@ -133,14 +133,12 @@ pprTop (CmmData _section (Statics lbl lits)) = -- as many jumps as possible into fall throughs. -- -pprBBlock :: CmmBasicBlock -> SDoc -pprBBlock (BasicBlock lbl stmts) = - if null stmts then - pprTrace "pprC.pprBBlock: curious empty code block for" - (pprBlockId lbl) empty - else - nest 4 (pprBlockId lbl <> colon) $$ - nest 8 (vcat (map pprStmt stmts)) +pprBBlock :: CmmBlock -> SDoc +pprBBlock block = + nest 4 (pprBlockId lbl <> colon) $$ + nest 8 (vcat (map pprStmt (blockToList nodes)) $$ pprStmt last) + where + (CmmEntry lbl, nodes, last) = blockSplit block -- -------------------------------------------------------------------------- -- Info tables. Just arrays of words. @@ -165,13 +163,11 @@ pprLocalness lbl | not $ externallyVisibleCLabel lbl = ptext (sLit "static ") -- Statements. -- -pprStmt :: CmmStmt -> SDoc +pprStmt :: CmmNode e x -> SDoc pprStmt stmt = sdocWithDynFlags $ \dflags -> case stmt of - CmmReturn -> panic "pprStmt: return statement should have been cps'd away" - CmmNop -> empty CmmComment _ -> empty -- (hang (ptext (sLit "/*")) 3 (ftext s)) $$ ptext (sLit "*/") -- XXX if the string contains "*/", we need to fix it -- XXX we probably want to emit these comments when @@ -191,14 +187,20 @@ pprStmt stmt = where rep = cmmExprType dflags src - CmmCall (CmmCallee fn cconv) results args ret -> + CmmUnsafeForeignCall target@(ForeignTarget fn conv) results args -> maybe_proto $$ fnCall where - cast_fn = parens (cCast (pprCFunType (char '*') cconv results args) fn) + (res_hints, arg_hints) = foreignTargetHints target + hresults = zip results res_hints + hargs = zip args arg_hints + + ForeignConvention cconv _ _ ret = conv + + cast_fn = parens (cCast (pprCFunType (char '*') cconv hresults hargs) fn) real_fun_proto lbl = char ';' <> - pprCFunType (ppr lbl) cconv results args <> + pprCFunType (ppr lbl) cconv hresults hargs <> noreturn_attr <> semi noreturn_attr = case ret of @@ -210,7 +212,7 @@ pprStmt stmt = case fn of CmmLit (CmmLabel lbl) | StdCallConv <- cconv -> - let myCall = pprCall (ppr lbl) cconv results args + let myCall = pprCall (ppr lbl) cconv hresults hargs in (real_fun_proto lbl, myCall) -- stdcall functions must be declared with -- a function type, otherwise the C compiler @@ -218,40 +220,44 @@ pprStmt stmt = -- can't add the @n suffix ourselves, because -- it isn't valid C. | CmmNeverReturns <- ret -> - let myCall = pprCall (ppr lbl) cconv results args + let myCall = pprCall (ppr lbl) cconv hresults hargs in (real_fun_proto lbl, myCall) | not (isMathFun lbl) -> - pprForeignCall (ppr lbl) cconv results args + pprForeignCall (ppr lbl) cconv hresults hargs _ -> (empty {- no proto -}, - pprCall cast_fn cconv results args <> semi) + pprCall cast_fn cconv hresults hargs <> semi) -- for a dynamic call, no declaration is necessary. - CmmCall (CmmPrim _ (Just stmts)) _ _ _ -> - vcat $ map pprStmt stmts - - CmmCall (CmmPrim op _) results args _ret -> + CmmUnsafeForeignCall target@(PrimTarget op) results args -> proto $$ fn_call where cconv = CCallConv fn = pprCallishMachOp_for_C op + + (res_hints, arg_hints) = foreignTargetHints target + hresults = zip results res_hints + hargs = zip args arg_hints + (proto, fn_call) -- The mem primops carry an extra alignment arg, must drop it. -- We could maybe emit an alignment directive using this info. -- We also need to cast mem primops to prevent conflicts with GCC -- builtins (see bug #5967). | op `elem` [MO_Memcpy, MO_Memset, MO_Memmove] - = pprForeignCall fn cconv results (init args) + = pprForeignCall fn cconv hresults (init hargs) | otherwise - = (empty, pprCall fn cconv results args) + = (empty, pprCall fn cconv hresults hargs) CmmBranch ident -> pprBranch ident - CmmCondBranch expr ident -> pprCondBranch expr ident - CmmJump lbl _ -> mkJMP_(pprExpr lbl) <> semi + CmmCondBranch expr yes no -> pprCondBranch expr yes no + CmmCall { cml_target = expr } -> mkJMP_ (pprExpr expr) <> semi CmmSwitch arg ids -> sdocWithDynFlags $ \dflags -> pprSwitch dflags arg ids -pprForeignCall :: SDoc -> CCallConv -> [HintedCmmFormal] -> [HintedCmmActual] +type Hinted a = (a, ForeignHint) + +pprForeignCall :: SDoc -> CCallConv -> [Hinted CmmFormal] -> [Hinted CmmActual] -> (SDoc, SDoc) pprForeignCall fn cconv results args = (proto, fn_call) where @@ -263,14 +269,14 @@ pprForeignCall fn cconv results args = (proto, fn_call) cast_fn = parens (parens (pprCFunType (char '*') cconv results args) <> fn) proto = ptext (sLit ";EF_(") <> fn <> char ')' <> semi -pprCFunType :: SDoc -> CCallConv -> [HintedCmmFormal] -> [HintedCmmActual] -> SDoc +pprCFunType :: SDoc -> CCallConv -> [Hinted CmmFormal] -> [Hinted CmmActual] -> SDoc pprCFunType ppr_fn cconv ress args = sdocWithDynFlags $ \dflags -> let res_type [] = ptext (sLit "void") - res_type [CmmHinted one hint] = machRepHintCType (localRegType one) hint + res_type [(one, hint)] = machRepHintCType (localRegType one) hint res_type _ = panic "pprCFunType: only void or 1 return value supported" - arg_type (CmmHinted expr hint) = machRepHintCType (cmmExprType dflags expr) hint + arg_type (expr, hint) = machRepHintCType (cmmExprType dflags expr) hint in res_type ress <+> parens (ccallConvAttribute cconv <> ppr_fn) <> parens (commafy (map arg_type args)) @@ -283,11 +289,11 @@ pprBranch ident = ptext (sLit "goto") <+> pprBlockId ident <> semi -- --------------------------------------------------------------------- -- conditional branches to local labels -pprCondBranch :: CmmExpr -> BlockId -> SDoc -pprCondBranch expr ident +pprCondBranch :: CmmExpr -> BlockId -> BlockId -> SDoc +pprCondBranch expr yes no = hsep [ ptext (sLit "if") , parens(pprExpr expr) , - ptext (sLit "goto") , (pprBlockId ident) <> semi ] - + ptext (sLit "goto"), pprBlockId yes, + ptext (sLit "else"), pprBlockId no <> semi ] -- --------------------------------------------------------------------- -- a local table branch @@ -831,7 +837,7 @@ pprLocalReg (LocalReg uniq _) = char '_' <> ppr uniq -- ----------------------------------------------------------------------------- -- Foreign Calls -pprCall :: SDoc -> CCallConv -> [HintedCmmFormal] -> [HintedCmmActual] -> SDoc +pprCall :: SDoc -> CCallConv -> [Hinted CmmFormal] -> [Hinted CmmActual] -> SDoc pprCall ppr_fn cconv results args | not (is_cishCC cconv) = panic $ "pprCall: unknown calling convention" @@ -841,18 +847,18 @@ pprCall ppr_fn cconv results args ppr_assign results (ppr_fn <> parens (commafy (map pprArg args))) <> semi where ppr_assign [] rhs = rhs - ppr_assign [CmmHinted one hint] rhs + ppr_assign [(one,hint)] rhs = pprLocalReg one <> ptext (sLit " = ") <> pprUnHint hint (localRegType one) <> rhs ppr_assign _other _rhs = panic "pprCall: multiple results" - pprArg (CmmHinted expr AddrHint) + pprArg (expr, AddrHint) = cCast (ptext (sLit "void *")) expr -- see comment by machRepHintCType below - pprArg (CmmHinted expr SignedHint) + pprArg (expr, SignedHint) = sdocWithDynFlags $ \dflags -> cCast (machRep_S_CType $ typeWidth $ cmmExprType dflags expr) expr - pprArg (CmmHinted expr _other) + pprArg (expr, _other) = pprExpr expr pprUnHint AddrHint rep = parens (machRepCType rep) @@ -871,7 +877,7 @@ is_cishCC PrimCallConv = False -- Find and print local and external declarations for a list of -- Cmm statements. -- -pprTempAndExternDecls :: [CmmBasicBlock] -> (SDoc{-temps-}, SDoc{-externs-}) +pprTempAndExternDecls :: [CmmBlock] -> (SDoc{-temps-}, SDoc{-externs-}) pprTempAndExternDecls stmts = (vcat (map pprTempDecl (uniqSetToList temps)), vcat (map (pprExternDecl False{-ToDo-}) (Map.keys lbls))) @@ -930,8 +936,9 @@ te_Static :: CmmStatic -> TE () te_Static (CmmStaticLit lit) = te_Lit lit te_Static _ = return () -te_BB :: CmmBasicBlock -> TE () -te_BB (BasicBlock _ ss) = mapM_ te_Stmt ss +te_BB :: CmmBlock -> TE () +te_BB block = mapM_ te_Stmt (blockToList mid) >> te_Stmt last + where (_, mid, last) = blockSplit block te_Lit :: CmmLit -> TE () te_Lit (CmmLabel l) = te_lbl l @@ -939,21 +946,21 @@ te_Lit (CmmLabelOff l _) = te_lbl l te_Lit (CmmLabelDiffOff l1 _ _) = te_lbl l1 te_Lit _ = return () -te_Stmt :: CmmStmt -> TE () +te_Stmt :: CmmNode e x -> 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 target rs es _) = do te_Target target - mapM_ (te_temp.hintlessCmm) rs - mapM_ (te_Expr.hintlessCmm) es -te_Stmt (CmmCondBranch e _) = te_Expr e +te_Stmt (CmmUnsafeForeignCall target rs es) + = do te_Target target + mapM_ te_temp rs + mapM_ te_Expr es +te_Stmt (CmmCondBranch e _ _) = te_Expr e te_Stmt (CmmSwitch e _) = te_Expr e -te_Stmt (CmmJump e _) = te_Expr e +te_Stmt (CmmCall { cml_target = e }) = te_Expr e te_Stmt _ = return () -te_Target :: CmmCallTarget -> TE () -te_Target (CmmCallee {}) = return () -te_Target (CmmPrim _ Nothing) = return () -te_Target (CmmPrim _ (Just stmts)) = mapM_ te_Stmt stmts +te_Target :: ForeignTarget -> TE () +te_Target (ForeignTarget e _) = te_Expr e +te_Target (PrimTarget{}) = return () te_Expr :: CmmExpr -> TE () te_Expr (CmmLit lit) = te_Lit lit |