summaryrefslogtreecommitdiff
path: root/compiler/cmm/PprC.hs
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2012-11-12 11:47:51 +0000
committerSimon Marlow <marlowsd@gmail.com>2012-11-12 15:20:25 +0000
commitd92bd17ffd8715f77fd49de0fed6e39c8d0ec28b (patch)
treea721be9b82241dbcce19f66defcbfa41ffefe581 /compiler/cmm/PprC.hs
parent121768dec30facc5c9ff94cf84bc9eac71e7290b (diff)
downloadhaskell-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.hs131
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