diff options
Diffstat (limited to 'compiler/GHC/CmmToC.hs')
-rw-r--r-- | compiler/GHC/CmmToC.hs | 516 |
1 files changed, 265 insertions, 251 deletions
diff --git a/compiler/GHC/CmmToC.hs b/compiler/GHC/CmmToC.hs index 7944f6a0fc..71b0793057 100644 --- a/compiler/GHC/CmmToC.hs +++ b/compiler/GHC/CmmToC.hs @@ -1,4 +1,5 @@ {-# LANGUAGE CPP, DeriveFunctor, GADTs, PatternSynonyms #-} +{-# LANGUAGE LambdaCase #-} ----------------------------------------------------------------------------- -- @@ -68,7 +69,7 @@ import Data.Array.ST -- Top level writeC :: DynFlags -> Handle -> RawCmmGroup -> IO () -writeC dflags handle cmm = printForC dflags handle (pprC cmm $$ blankLine) +writeC dflags handle cmm = printForC dflags handle (pprC dflags cmm $$ blankLine) -- -------------------------------------------------------------------------- -- Now do some real work @@ -76,57 +77,59 @@ writeC dflags handle cmm = printForC dflags handle (pprC cmm $$ blankLine) -- for fun, we could call cmmToCmm over the tops... -- -pprC :: RawCmmGroup -> SDoc -pprC tops = vcat $ intersperse blankLine $ map pprTop tops +pprC :: DynFlags -> RawCmmGroup -> SDoc +pprC dflags tops = vcat $ intersperse blankLine $ map (pprTop dflags) tops -- -- top level procs -- -pprTop :: RawCmmDecl -> SDoc -pprTop (CmmProc infos clbl _in_live_regs graph) = - +pprTop :: DynFlags -> RawCmmDecl -> SDoc +pprTop dflags = \case + (CmmProc infos clbl _in_live_regs graph) -> (case mapLookup (g_entry graph) infos of Nothing -> empty Just (RawCmmStatics info_clbl info_dat) -> - pprDataExterns info_dat $$ - pprWordArray info_is_in_rodata info_clbl info_dat) $$ + pprDataExterns platform info_dat $$ + pprWordArray dflags info_is_in_rodata info_clbl info_dat) $$ (vcat [ blankLine, extern_decls, (if (externallyVisibleCLabel clbl) then mkFN_ else mkIF_) (ppr clbl) <+> lbrace, nest 8 temp_decls, - vcat (map pprBBlock blocks), + vcat (map (pprBBlock dflags) blocks), rbrace ] ) - where + where -- info tables are always in .rodata info_is_in_rodata = True blocks = toBlockListEntryFirst graph - (temp_decls, extern_decls) = pprTempAndExternDecls blocks + (temp_decls, extern_decls) = pprTempAndExternDecls platform blocks --- Chunks of static data. + -- Chunks of static data. --- We only handle (a) arrays of word-sized things and (b) strings. + -- We only handle (a) arrays of word-sized things and (b) strings. -pprTop (CmmData section (RawCmmStatics lbl [CmmString str])) = - pprExternDecl lbl $$ - hcat [ - pprLocalness lbl, pprConstness (isSecConstant section), text "char ", ppr lbl, - text "[] = ", pprStringInCStyle str, semi - ] + (CmmData section (RawCmmStatics lbl [CmmString str])) -> + pprExternDecl platform lbl $$ + hcat [ + pprLocalness lbl, pprConstness (isSecConstant section), text "char ", ppr lbl, + text "[] = ", pprStringInCStyle str, semi + ] -pprTop (CmmData section (RawCmmStatics lbl [CmmUninitialised size])) = - pprExternDecl lbl $$ - hcat [ - pprLocalness lbl, pprConstness (isSecConstant section), text "char ", ppr lbl, - brackets (int size), semi - ] + (CmmData section (RawCmmStatics lbl [CmmUninitialised size])) -> + pprExternDecl platform lbl $$ + hcat [ + pprLocalness lbl, pprConstness (isSecConstant section), text "char ", ppr lbl, + brackets (int size), semi + ] -pprTop (CmmData section (RawCmmStatics lbl lits)) = - pprDataExterns lits $$ - pprWordArray (isSecConstant section) lbl lits + (CmmData section (RawCmmStatics lbl lits)) -> + pprDataExterns platform lits $$ + pprWordArray dflags (isSecConstant section) lbl lits + where + platform = targetPlatform dflags -- -------------------------------------------------------------------------- -- BasicBlocks are self-contained entities: they always end in a jump. @@ -135,10 +138,10 @@ pprTop (CmmData section (RawCmmStatics lbl lits)) = -- as many jumps as possible into fall throughs. -- -pprBBlock :: CmmBlock -> SDoc -pprBBlock block = +pprBBlock :: DynFlags -> CmmBlock -> SDoc +pprBBlock dflags block = nest 4 (pprBlockId (entryLabel block) <> colon) $$ - nest 8 (vcat (map pprStmt (blockToList nodes)) $$ pprStmt last) + nest 8 (vcat (map (pprStmt dflags) (blockToList nodes)) $$ pprStmt dflags last) where (_, nodes, last) = blockSplit block @@ -146,18 +149,19 @@ pprBBlock block = -- Info tables. Just arrays of words. -- See codeGen/ClosureInfo, and nativeGen/PprMach -pprWordArray :: Bool -> CLabel -> [CmmStatic] -> SDoc -pprWordArray is_ro lbl ds - = sdocWithDynFlags $ \dflags -> - -- TODO: align closures only - pprExternDecl lbl $$ +pprWordArray :: DynFlags -> Bool -> CLabel -> [CmmStatic] -> SDoc +pprWordArray dflags is_ro lbl ds + = -- TODO: align closures only + pprExternDecl platform lbl $$ hcat [ pprLocalness lbl, pprConstness is_ro, text "StgWord" , space, ppr lbl, text "[]" -- See Note [StgWord alignment] - , pprAlignment (wordWidth dflags) + , pprAlignment (wordWidth platform) , text "= {" ] $$ nest 8 (commafy (pprStatics dflags ds)) $$ text "};" + where + platform = targetPlatform dflags pprAlignment :: Width -> SDoc pprAlignment words = @@ -195,10 +199,9 @@ pprConstness is_ro | is_ro = text "const " -- Statements. -- -pprStmt :: CmmNode e x -> SDoc +pprStmt :: DynFlags -> CmmNode e x -> SDoc -pprStmt stmt = - sdocWithDynFlags $ \dflags -> +pprStmt dflags stmt = case stmt of CmmEntry{} -> empty CmmComment _ -> empty -- (hang (text "/*") 3 (ftext s)) $$ ptext (sLit "*/") @@ -213,15 +216,16 @@ pprStmt stmt = CmmAssign dest src -> pprAssign dflags dest src CmmStore dest src - | typeWidth rep == W64 && wordWidth dflags /= W64 + | typeWidth rep == W64 && wordWidth platform /= W64 -> (if isFloatType rep then text "ASSIGN_DBL" else ptext (sLit ("ASSIGN_Word64"))) <> - parens (mkP_ <> pprExpr1 dest <> comma <> pprExpr src) <> semi + parens (mkP_ <> pprExpr1 dflags dest <> comma <> pprExpr dflags src) <> semi | otherwise - -> hsep [ pprExpr (CmmLoad dest rep), equals, pprExpr src <> semi ] + -> hsep [ pprExpr dflags (CmmLoad dest rep), equals, pprExpr dflags src <> semi ] where - rep = cmmExprType dflags src + rep = cmmExprType platform src + platform = targetPlatform dflags CmmUnsafeForeignCall target@(ForeignTarget fn conv) results args -> fnCall @@ -229,28 +233,29 @@ pprStmt stmt = (res_hints, arg_hints) = foreignTargetHints target hresults = zip results res_hints hargs = zip args arg_hints + platform = targetPlatform dflags ForeignConvention cconv _ _ ret = conv - cast_fn = parens (cCast (pprCFunType (char '*') cconv hresults hargs) fn) + cast_fn = parens (cCast dflags (pprCFunType platform (char '*') cconv hresults hargs) fn) -- See wiki:commentary/compiler/backends/ppr-c#prototypes fnCall = case fn of CmmLit (CmmLabel lbl) | StdCallConv <- cconv -> - pprCall (ppr lbl) cconv hresults hargs + pprCall dflags (ppr lbl) cconv hresults hargs -- stdcall functions must be declared with -- a function type, otherwise the C compiler -- doesn't add the @n suffix to the label. We -- can't add the @n suffix ourselves, because -- it isn't valid C. | CmmNeverReturns <- ret -> - pprCall cast_fn cconv hresults hargs <> semi + pprCall dflags cast_fn cconv hresults hargs <> semi | not (isMathFun lbl) -> - pprForeignCall (ppr lbl) cconv hresults hargs + pprForeignCall dflags (ppr lbl) cconv hresults hargs _ -> - pprCall cast_fn cconv hresults hargs <> semi + pprCall dflags cast_fn cconv hresults hargs <> semi -- for a dynamic call, no declaration is necessary. CmmUnsafeForeignCall (PrimTarget MO_Touch) _results _args -> empty @@ -273,39 +278,38 @@ pprStmt stmt = -- builtins (see bug #5967). | Just _align <- machOpMemcpyishAlign op = (text ";EFF_(" <> fn <> char ')' <> semi) $$ - pprForeignCall fn cconv hresults hargs + pprForeignCall dflags fn cconv hresults hargs | otherwise - = pprCall fn cconv hresults hargs + = pprCall dflags fn cconv hresults hargs - CmmBranch ident -> pprBranch ident - 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 + CmmBranch ident -> pprBranch ident + CmmCondBranch expr yes no _ -> pprCondBranch dflags expr yes no + CmmCall { cml_target = expr } -> mkJMP_ (pprExpr dflags expr) <> semi + CmmSwitch arg ids -> pprSwitch dflags arg ids _other -> pprPanic "PprC.pprStmt" (ppr stmt) type Hinted a = (a, ForeignHint) -pprForeignCall :: SDoc -> CCallConv -> [Hinted CmmFormal] -> [Hinted CmmActual] +pprForeignCall :: DynFlags -> SDoc -> CCallConv -> [Hinted CmmFormal] -> [Hinted CmmActual] -> SDoc -pprForeignCall fn cconv results args = fn_call +pprForeignCall dflags fn cconv results args = fn_call where + platform = targetPlatform dflags fn_call = braces ( - pprCFunType (char '*' <> text "ghcFunPtr") cconv results args <> semi + pprCFunType platform (char '*' <> text "ghcFunPtr") cconv results args <> semi $$ text "ghcFunPtr" <+> equals <+> cast_fn <> semi - $$ pprCall (text "ghcFunPtr") cconv results args <> semi + $$ pprCall dflags (text "ghcFunPtr") cconv results args <> semi ) - cast_fn = parens (parens (pprCFunType (char '*') cconv results args) <> fn) + cast_fn = parens (parens (pprCFunType platform (char '*') cconv results args) <> fn) -pprCFunType :: SDoc -> CCallConv -> [Hinted CmmFormal] -> [Hinted CmmActual] -> SDoc -pprCFunType ppr_fn cconv ress args - = sdocWithDynFlags $ \dflags -> - let res_type [] = text "void" - res_type [(one, hint)] = machRepHintCType (localRegType one) hint +pprCFunType :: Platform -> SDoc -> CCallConv -> [Hinted CmmFormal] -> [Hinted CmmActual] -> SDoc +pprCFunType platform ppr_fn cconv ress args + = let res_type [] = text "void" + res_type [(one, hint)] = machRepHintCType platform (localRegType one) hint res_type _ = panic "pprCFunType: only void or 1 return value supported" - arg_type (expr, hint) = machRepHintCType (cmmExprType dflags expr) hint + arg_type (expr, hint) = machRepHintCType platform (cmmExprType platform expr) hint in res_type ress <+> parens (ccallConvAttribute cconv <> ppr_fn) <> parens (commafy (map arg_type args)) @@ -318,9 +322,9 @@ pprBranch ident = text "goto" <+> pprBlockId ident <> semi -- --------------------------------------------------------------------- -- conditional branches to local labels -pprCondBranch :: CmmExpr -> BlockId -> BlockId -> SDoc -pprCondBranch expr yes no - = hsep [ text "if" , parens(pprExpr expr) , +pprCondBranch :: DynFlags -> CmmExpr -> BlockId -> BlockId -> SDoc +pprCondBranch dflags expr yes no + = hsep [ text "if" , parens(pprExpr dflags expr) , text "goto", pprBlockId yes <> semi, text "else goto", pprBlockId no <> semi ] @@ -331,20 +335,21 @@ pprCondBranch expr yes no -- pprSwitch :: DynFlags -> CmmExpr -> SwitchTargets -> SDoc pprSwitch dflags e ids - = (hang (text "switch" <+> parens ( pprExpr e ) <+> lbrace) + = (hang (text "switch" <+> parens ( pprExpr dflags e ) <+> lbrace) 4 (vcat ( map caseify pairs ) $$ def)) $$ rbrace where (pairs, mbdef) = switchTargetsFallThrough ids + platform = targetPlatform dflags -- fall through case caseify (ix:ixs, ident) = vcat (map do_fallthrough ixs) $$ final_branch ix where do_fallthrough ix = - hsep [ text "case" , pprHexVal ix (wordWidth dflags) <> colon , + hsep [ text "case" , pprHexVal dflags ix (wordWidth platform) <> colon , text "/* fall through */" ] final_branch ix = - hsep [ text "case" , pprHexVal ix (wordWidth dflags) <> colon , + hsep [ text "case" , pprHexVal dflags ix (wordWidth platform) <> colon , text "goto" , (pprBlockId ident) <> semi ] caseify (_ , _ ) = panic "pprSwitch: switch with no cases!" @@ -366,72 +371,73 @@ pprSwitch dflags e ids -- -- (similar invariants apply to the rest of the pretty printer). -pprExpr :: CmmExpr -> SDoc -pprExpr e = case e of - CmmLit lit -> pprLit lit - - - CmmLoad e ty -> sdocWithDynFlags $ \dflags -> pprLoad dflags e ty +pprExpr :: DynFlags -> CmmExpr -> SDoc +pprExpr dflags e = case e of + CmmLit lit -> pprLit dflags lit + CmmLoad e ty -> pprLoad dflags e ty CmmReg reg -> pprCastReg reg CmmRegOff reg 0 -> pprCastReg reg -- CmmRegOff is an alias of MO_Add - CmmRegOff reg i -> sdocWithDynFlags $ \dflags -> - pprCastReg reg <> char '+' <> - pprHexVal (fromIntegral i) (wordWidth dflags) + CmmRegOff reg i -> pprCastReg reg <> char '+' <> + pprHexVal dflags (fromIntegral i) (wordWidth platform) - CmmMachOp mop args -> pprMachOpApp mop args + CmmMachOp mop args -> pprMachOpApp dflags mop args CmmStackSlot _ _ -> panic "pprExpr: CmmStackSlot not supported!" + where + platform = targetPlatform dflags pprLoad :: DynFlags -> CmmExpr -> CmmType -> SDoc pprLoad dflags e ty - | width == W64, wordWidth dflags /= W64 + | width == W64, wordWidth platform /= W64 = (if isFloatType ty then text "PK_DBL" else text "PK_Word64") - <> parens (mkP_ <> pprExpr1 e) + <> parens (mkP_ <> pprExpr1 dflags e) | otherwise = case e of - CmmReg r | isPtrReg r && width == wordWidth dflags && not (isFloatType ty) + CmmReg r | isPtrReg r && width == wordWidth platform && not (isFloatType ty) -> char '*' <> pprAsPtrReg r - CmmRegOff r 0 | isPtrReg r && width == wordWidth dflags && not (isFloatType ty) + CmmRegOff r 0 | isPtrReg r && width == wordWidth platform && not (isFloatType ty) -> char '*' <> pprAsPtrReg r - CmmRegOff r off | isPtrReg r && width == wordWidth dflags - , off `rem` wORD_SIZE dflags == 0 && not (isFloatType ty) + CmmRegOff r off | isPtrReg r && width == wordWidth platform + , off `rem` platformWordSizeInBytes platform == 0 && not (isFloatType ty) -- 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 dflags)) + -> pprAsPtrReg r <> brackets (ppr (off `shiftR` wordShift platform)) - _other -> cLoad (targetPlatform dflags) e ty + _other -> cLoad dflags e ty where width = typeWidth ty + platform = targetPlatform dflags -pprExpr1 :: CmmExpr -> SDoc -pprExpr1 (CmmLit lit) = pprLit1 lit -pprExpr1 e@(CmmReg _reg) = pprExpr e -pprExpr1 other = parens (pprExpr other) +pprExpr1 :: DynFlags -> CmmExpr -> SDoc +pprExpr1 dflags e = case e of + CmmLit lit -> pprLit1 dflags lit + CmmReg _reg -> pprExpr dflags e + _ -> parens (pprExpr dflags e) -- -------------------------------------------------------------------------- -- MachOp applications -pprMachOpApp :: MachOp -> [CmmExpr] -> SDoc +pprMachOpApp :: DynFlags -> MachOp -> [CmmExpr] -> SDoc -pprMachOpApp op args +pprMachOpApp dflags op args | isMulMayOfloOp op - = text "mulIntMayOflo" <> parens (commafy (map pprExpr args)) + = text "mulIntMayOflo" <> parens (commafy (map (pprExpr dflags) args)) where isMulMayOfloOp (MO_U_MulMayOflo _) = True isMulMayOfloOp (MO_S_MulMayOflo _) = True isMulMayOfloOp _ = False -pprMachOpApp mop args +pprMachOpApp dflags mop args | Just ty <- machOpNeedsCast mop - = ty <> parens (pprMachOpApp' mop args) + = ty <> parens (pprMachOpApp' dflags mop args) | otherwise - = pprMachOpApp' mop args + = pprMachOpApp' dflags 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 @@ -441,24 +447,23 @@ machOpNeedsCast mop | isComparisonMachOp mop = Just mkW_ | otherwise = Nothing -pprMachOpApp' :: MachOp -> [CmmExpr] -> SDoc -pprMachOpApp' mop args +pprMachOpApp' :: DynFlags -> MachOp -> [CmmExpr] -> SDoc +pprMachOpApp' dflags mop args = case args of -- dyadic - [x,y] -> pprArg x <+> pprMachOp_for_C mop <+> pprArg y + [x,y] -> pprArg x <+> pprMachOp_for_C platform mop <+> pprArg y -- unary - [x] -> pprMachOp_for_C mop <> parens (pprArg x) + [x] -> pprMachOp_for_C platform mop <> parens (pprArg x) _ -> panic "PprC.pprMachOp : machop with wrong number of args" where + platform = targetPlatform dflags -- Cast needed for signed integer ops - pprArg e | signedOp mop = sdocWithDynFlags $ \dflags -> - cCast (machRep_S_CType (typeWidth (cmmExprType dflags e))) e - | needsFCasts mop = sdocWithDynFlags $ \dflags -> - cCast (machRep_F_CType (typeWidth (cmmExprType dflags e))) e - | otherwise = pprExpr1 e + pprArg e | signedOp mop = cCast dflags (machRep_S_CType platform (typeWidth (cmmExprType platform e))) e + | needsFCasts mop = cCast dflags (machRep_F_CType (typeWidth (cmmExprType platform e))) e + | otherwise = pprExpr1 dflags e needsFCasts (MO_F_Eq _) = False needsFCasts (MO_F_Ne _) = False needsFCasts (MO_F_Neg _) = True @@ -468,9 +473,9 @@ pprMachOpApp' mop args -- -------------------------------------------------------------------------- -- Literals -pprLit :: CmmLit -> SDoc -pprLit lit = case lit of - CmmInt i rep -> pprHexVal i rep +pprLit :: DynFlags -> CmmLit -> SDoc +pprLit dflags lit = case lit of + CmmInt i rep -> pprHexVal dflags i rep CmmFloat f w -> parens (machRep_F_CType w) <> str where d = fromRational f :: Double @@ -496,71 +501,75 @@ pprLit lit = case lit of where pprCLabelAddr lbl = char '&' <> ppr lbl -pprLit1 :: CmmLit -> SDoc -pprLit1 lit@(CmmLabelOff _ _) = parens (pprLit lit) -pprLit1 lit@(CmmLabelDiffOff _ _ _ _) = parens (pprLit lit) -pprLit1 lit@(CmmFloat _ _) = parens (pprLit lit) -pprLit1 other = pprLit other +pprLit1 :: DynFlags -> CmmLit -> SDoc +pprLit1 dflags lit = case lit of + (CmmLabelOff _ _) -> parens (pprLit dflags lit) + (CmmLabelDiffOff _ _ _ _) -> parens (pprLit dflags lit) + (CmmFloat _ _) -> parens (pprLit dflags lit) + _ -> pprLit dflags lit -- --------------------------------------------------------------------------- -- Static data pprStatics :: DynFlags -> [CmmStatic] -> [SDoc] -pprStatics _ [] = [] -pprStatics dflags (CmmStaticLit (CmmFloat f W32) : rest) - -- odd numbers of floats are padded to a word by mkVirtHeapOffsetsWithPadding - | wORD_SIZE dflags == 8, CmmStaticLit (CmmInt 0 W32) : rest' <- rest - = pprLit1 (floatToWord dflags f) : pprStatics dflags rest' - -- adjacent floats aren't padded but combined into a single word - | wORD_SIZE dflags == 8, CmmStaticLit (CmmFloat g W32) : rest' <- rest - = pprLit1 (floatPairToWord dflags f g) : pprStatics dflags rest' - | wORD_SIZE dflags == 4 - = pprLit1 (floatToWord dflags f) : pprStatics dflags rest - | otherwise - = pprPanic "pprStatics: float" (vcat (map ppr' rest)) - where ppr' (CmmStaticLit l) = sdocWithDynFlags $ \dflags -> - ppr (cmmLitType dflags l) - ppr' _other = text "bad static!" -pprStatics dflags (CmmStaticLit (CmmFloat f W64) : rest) - = map pprLit1 (doubleToWords dflags f) ++ pprStatics dflags rest - -pprStatics dflags (CmmStaticLit (CmmInt i W64) : rest) - | wordWidth dflags == W32 - = if wORDS_BIGENDIAN dflags - then pprStatics dflags (CmmStaticLit (CmmInt q W32) : - CmmStaticLit (CmmInt r W32) : rest) - else pprStatics dflags (CmmStaticLit (CmmInt r W32) : - CmmStaticLit (CmmInt q W32) : rest) - where r = i .&. 0xffffffff - q = i `shiftR` 32 -pprStatics dflags (CmmStaticLit (CmmInt a W32) : - CmmStaticLit (CmmInt b W32) : rest) - | wordWidth dflags == W64 - = if wORDS_BIGENDIAN dflags - then pprStatics dflags (CmmStaticLit (CmmInt ((shiftL a 32) .|. b) W64) : - rest) - else pprStatics dflags (CmmStaticLit (CmmInt ((shiftL b 32) .|. a) W64) : - rest) -pprStatics dflags (CmmStaticLit (CmmInt a W16) : - CmmStaticLit (CmmInt b W16) : rest) - | wordWidth dflags == W32 - = if wORDS_BIGENDIAN dflags - then pprStatics dflags (CmmStaticLit (CmmInt ((shiftL a 16) .|. b) W32) : - rest) - else pprStatics dflags (CmmStaticLit (CmmInt ((shiftL b 16) .|. a) W32) : - rest) -pprStatics dflags (CmmStaticLit (CmmInt _ w) : _) - | w /= wordWidth dflags - = pprPanic "pprStatics: cannot emit a non-word-sized static literal" (ppr w) -pprStatics dflags (CmmStaticLit lit : rest) - = pprLit1 lit : pprStatics dflags rest -pprStatics _ (other : _) - = pprPanic "pprStatics: other" (pprStatic other) - -pprStatic :: CmmStatic -> SDoc -pprStatic s = case s of - - CmmStaticLit lit -> nest 4 (pprLit lit) +pprStatics dflags = pprStatics' + where + platform = targetPlatform dflags + pprStatics' = \case + [] -> [] + (CmmStaticLit (CmmFloat f W32) : rest) + -- odd numbers of floats are padded to a word by mkVirtHeapOffsetsWithPadding + | wordWidth platform == W64, CmmStaticLit (CmmInt 0 W32) : rest' <- rest + -> pprLit1 dflags (floatToWord dflags f) : pprStatics' rest' + -- adjacent floats aren't padded but combined into a single word + | wordWidth platform == W64, CmmStaticLit (CmmFloat g W32) : rest' <- rest + -> pprLit1 dflags (floatPairToWord dflags f g) : pprStatics' rest' + | wordWidth platform == W32 + -> pprLit1 dflags (floatToWord dflags f) : pprStatics' rest + | otherwise + -> pprPanic "pprStatics: float" (vcat (map ppr' rest)) + where ppr' (CmmStaticLit l) = ppr (cmmLitType platform l) + ppr' _other = text "bad static!" + + (CmmStaticLit (CmmFloat f W64) : rest) + -> map (pprLit1 dflags) (doubleToWords dflags f) ++ pprStatics' rest + + (CmmStaticLit (CmmInt i W64) : rest) + | wordWidth platform == W32 + -> if wORDS_BIGENDIAN dflags + then pprStatics' (CmmStaticLit (CmmInt q W32) : + CmmStaticLit (CmmInt r W32) : rest) + else pprStatics' (CmmStaticLit (CmmInt r W32) : + CmmStaticLit (CmmInt q W32) : rest) + where r = i .&. 0xffffffff + q = i `shiftR` 32 + + (CmmStaticLit (CmmInt a W32) : CmmStaticLit (CmmInt b W32) : rest) + | wordWidth platform == W64 + -> if wORDS_BIGENDIAN dflags + then pprStatics' (CmmStaticLit (CmmInt ((shiftL a 32) .|. b) W64) : rest) + else pprStatics' (CmmStaticLit (CmmInt ((shiftL b 32) .|. a) W64) : rest) + + (CmmStaticLit (CmmInt a W16) : CmmStaticLit (CmmInt b W16) : rest) + | wordWidth platform == W32 + -> if wORDS_BIGENDIAN dflags + then pprStatics' (CmmStaticLit (CmmInt ((shiftL a 16) .|. b) W32) : rest) + else pprStatics' (CmmStaticLit (CmmInt ((shiftL b 16) .|. a) W32) : rest) + + (CmmStaticLit (CmmInt _ w) : _) + | w /= wordWidth platform + -> pprPanic "pprStatics: cannot emit a non-word-sized static literal" (ppr w) + + (CmmStaticLit lit : rest) + -> pprLit1 dflags lit : pprStatics' rest + + (other : _) + -> pprPanic "pprStatics: other" (pprStatic dflags other) + +pprStatic :: DynFlags -> CmmStatic -> SDoc +pprStatic dflags s = case s of + + CmmStaticLit lit -> nest 4 (pprLit dflags lit) CmmUninitialised i -> nest 4 (mkC_ <> brackets (int i)) -- these should be inlined, like the old .hc @@ -577,9 +586,9 @@ pprBlockId b = char '_' <> ppr (getUnique b) -- Print a MachOp in a way suitable for emitting via C. -- -pprMachOp_for_C :: MachOp -> SDoc +pprMachOp_for_C :: Platform -> MachOp -> SDoc -pprMachOp_for_C mop = case mop of +pprMachOp_for_C platform mop = case mop of -- Integer operations MO_Add _ -> char '+' @@ -640,19 +649,19 @@ pprMachOp_for_C mop = case mop of -- noop casts MO_UU_Conv from to | from == to -> empty - MO_UU_Conv _from to -> parens (machRep_U_CType to) + MO_UU_Conv _from to -> parens (machRep_U_CType platform to) MO_SS_Conv from to | from == to -> empty - MO_SS_Conv _from to -> parens (machRep_S_CType to) + MO_SS_Conv _from to -> parens (machRep_S_CType platform to) MO_XX_Conv from to | from == to -> empty - MO_XX_Conv _from to -> parens (machRep_U_CType to) + MO_XX_Conv _from to -> parens (machRep_U_CType platform to) MO_FF_Conv from to | from == to -> empty MO_FF_Conv _from to -> parens (machRep_F_CType to) MO_SF_Conv _from to -> parens (machRep_F_CType to) - MO_FS_Conv _from to -> parens (machRep_S_CType to) + MO_FS_Conv _from to -> parens (machRep_S_CType platform to) MO_S_MulMayOflo _ -> pprTrace "offending mop:" (text "MO_S_MulMayOflo") @@ -875,10 +884,11 @@ pprAssign _ r1 (CmmReg r2) -- dest is a reg, rhs is a CmmRegOff pprAssign dflags r1 (CmmRegOff r2 off) - | isPtrReg r1 && isPtrReg r2 && (off `rem` wORD_SIZE dflags == 0) + | isPtrReg r1 && isPtrReg r2 && (off `rem` platformWordSizeInBytes platform == 0) = hcat [ pprAsPtrReg r1, equals, pprAsPtrReg r2, op, int off', semi ] where - off1 = off `shiftR` wordShift dflags + platform = targetPlatform dflags + off1 = off `shiftR` wordShift platform (op,off') | off >= 0 = (char '+', off1) | otherwise = (char '-', -off1) @@ -886,10 +896,10 @@ pprAssign dflags r1 (CmmRegOff r2 off) -- dest is a reg, rhs is anything. -- 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 - | isFixedPtrReg r1 = mkAssign (mkP_ <> pprExpr1 r2) - | Just ty <- strangeRegType r1 = mkAssign (parens ty <> pprExpr1 r2) - | otherwise = mkAssign (pprExpr r2) +pprAssign dflags r1 r2 + | isFixedPtrReg r1 = mkAssign (mkP_ <> pprExpr1 dflags r2) + | Just ty <- strangeRegType r1 = mkAssign (parens ty <> pprExpr1 dflags r2) + | otherwise = mkAssign (pprExpr dflags r2) where mkAssign x = if r1 == CmmGlobal BaseReg then text "ASSIGN_BaseReg" <> parens x <> semi else pprReg r1 <> text " = " <> x <> semi @@ -988,8 +998,8 @@ pprLocalReg (LocalReg uniq _) = char '_' <> ppr uniq -- ----------------------------------------------------------------------------- -- Foreign Calls -pprCall :: SDoc -> CCallConv -> [Hinted CmmFormal] -> [Hinted CmmActual] -> SDoc -pprCall ppr_fn cconv results args +pprCall :: DynFlags -> SDoc -> CCallConv -> [Hinted CmmFormal] -> [Hinted CmmActual] -> SDoc +pprCall dflags ppr_fn cconv results args | not (is_cishCC cconv) = panic $ "pprCall: unknown calling convention" @@ -997,6 +1007,8 @@ pprCall ppr_fn cconv results args = ppr_assign results (ppr_fn <> parens (commafy (map pprArg args))) <> semi where + platform = targetPlatform dflags + ppr_assign [] rhs = rhs ppr_assign [(one,hint)] rhs = pprLocalReg one <> text " = " @@ -1004,16 +1016,15 @@ pprCall ppr_fn cconv results args ppr_assign _other _rhs = panic "pprCall: multiple results" pprArg (expr, AddrHint) - = cCast (text "void *") expr + = cCast dflags (text "void *") expr -- see comment by machRepHintCType below pprArg (expr, SignedHint) - = sdocWithDynFlags $ \dflags -> - cCast (machRep_S_CType $ typeWidth $ cmmExprType dflags expr) expr + = cCast dflags (machRep_S_CType platform $ typeWidth $ cmmExprType platform expr) expr pprArg (expr, _other) - = pprExpr expr + = pprExpr dflags expr - pprUnHint AddrHint rep = parens (machRepCType rep) - pprUnHint SignedHint rep = parens (machRepCType rep) + pprUnHint AddrHint rep = parens (machRepCType platform rep) + pprUnHint SignedHint rep = parens (machRepCType platform rep) pprUnHint _ _ = empty -- Currently we only have these two calling conventions, but this might @@ -1029,23 +1040,23 @@ is_cishCC JavaScriptCallConv = False -- Find and print local and external declarations for a list of -- Cmm statements. -- -pprTempAndExternDecls :: [CmmBlock] -> (SDoc{-temps-}, SDoc{-externs-}) -pprTempAndExternDecls stmts - = (pprUFM (getUniqSet temps) (vcat . map pprTempDecl), - vcat (map pprExternDecl (Map.keys lbls))) +pprTempAndExternDecls :: Platform -> [CmmBlock] -> (SDoc{-temps-}, SDoc{-externs-}) +pprTempAndExternDecls platform stmts + = (pprUFM (getUniqSet temps) (vcat . map (pprTempDecl platform)), + vcat (map (pprExternDecl platform) (Map.keys lbls))) where (temps, lbls) = runTE (mapM_ te_BB stmts) -pprDataExterns :: [CmmStatic] -> SDoc -pprDataExterns statics - = vcat (map pprExternDecl (Map.keys lbls)) +pprDataExterns :: Platform -> [CmmStatic] -> SDoc +pprDataExterns platform statics + = vcat (map (pprExternDecl platform) (Map.keys lbls)) where (_, lbls) = runTE (mapM_ te_Static statics) -pprTempDecl :: LocalReg -> SDoc -pprTempDecl l@(LocalReg _ rep) - = hcat [ machRepCType rep, space, pprLocalReg l, semi ] +pprTempDecl :: Platform -> LocalReg -> SDoc +pprTempDecl platform l@(LocalReg _ rep) + = hcat [ machRepCType platform rep, space, pprLocalReg l, semi ] -pprExternDecl :: CLabel -> SDoc -pprExternDecl lbl +pprExternDecl :: Platform -> CLabel -> SDoc +pprExternDecl platform lbl -- do not print anything for "known external" things | not (needsCDecl lbl) = empty | Just sz <- foreignLabelStdcallInfo lbl = stdcall_decl sz @@ -1072,9 +1083,9 @@ pprExternDecl lbl -- If the label we want to refer to is a stdcall function (on Windows) then -- we must generate an appropriate prototype for it, so that the C compiler will -- add the @n suffix to the label (#2276) - stdcall_decl sz = sdocWithDynFlags $ \dflags -> + stdcall_decl sz = text "extern __attribute__((stdcall)) void " <> ppr lbl - <> parens (commafy (replicate (sz `quot` wORD_SIZE dflags) (machRep_U_CType (wordWidth dflags)))) + <> parens (commafy (replicate (sz `quot` platformWordSizeInBytes platform) (machRep_U_CType platform (wordWidth platform)))) <> semi type TEState = (UniqSet LocalReg, Map CLabel ()) @@ -1142,18 +1153,18 @@ te_Reg _ = return () -- --------------------------------------------------------------------- -- C types for MachReps -cCast :: SDoc -> CmmExpr -> SDoc -cCast ty expr = parens ty <> pprExpr1 expr +cCast :: DynFlags -> SDoc -> CmmExpr -> SDoc +cCast dflags ty expr = parens ty <> pprExpr1 dflags expr -cLoad :: Platform -> CmmExpr -> CmmType -> SDoc -cLoad platform expr rep +cLoad :: DynFlags -> CmmExpr -> CmmType -> SDoc +cLoad dflags expr rep = if bewareLoadStoreAlignment (platformArch platform) - then let decl = machRepCType rep <+> text "x" <> semi + then let decl = machRepCType platform rep <+> text "x" <> semi struct = text "struct" <+> braces (decl) packed_attr = text "__attribute__((packed))" cast = parens (struct <+> packed_attr <> char '*') - in parens (cast <+> pprExpr1 expr) <> text "->x" - else char '*' <> parens (cCast (machRepPtrCType rep) expr) + in parens (cast <+> pprExpr1 dflags expr) <> text "->x" + else char '*' <> parens (cCast dflags (machRepPtrCType platform rep) expr) where -- On these platforms, unaligned loads are known to cause problems bewareLoadStoreAlignment ArchAlpha = True bewareLoadStoreAlignment ArchMipseb = True @@ -1166,53 +1177,54 @@ cLoad platform expr rep -- on unknown arches bewareLoadStoreAlignment ArchUnknown = True bewareLoadStoreAlignment _ = False + platform = targetPlatform dflags -isCmmWordType :: DynFlags -> CmmType -> Bool +isCmmWordType :: Platform -> CmmType -> Bool -- True of GcPtrReg/NonGcReg of native word size -isCmmWordType dflags ty = not (isFloatType ty) - && typeWidth ty == wordWidth dflags +isCmmWordType platform ty = not (isFloatType ty) + && typeWidth ty == wordWidth platform -- 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. -machRepHintCType :: CmmType -> ForeignHint -> SDoc -machRepHintCType _ AddrHint = text "void *" -machRepHintCType rep SignedHint = machRep_S_CType (typeWidth rep) -machRepHintCType rep _other = machRepCType rep - -machRepPtrCType :: CmmType -> SDoc -machRepPtrCType r - = sdocWithDynFlags $ \dflags -> - if isCmmWordType dflags r then text "P_" - else machRepCType r <> char '*' - -machRepCType :: CmmType -> SDoc -machRepCType ty | isFloatType ty = machRep_F_CType w - | otherwise = machRep_U_CType w - where - w = typeWidth ty +machRepHintCType :: Platform -> CmmType -> ForeignHint -> SDoc +machRepHintCType platform rep = \case + AddrHint -> text "void *" + SignedHint -> machRep_S_CType platform (typeWidth rep) + _other -> machRepCType platform rep + +machRepPtrCType :: Platform -> CmmType -> SDoc +machRepPtrCType platform r + = if isCmmWordType platform r + then text "P_" + else machRepCType platform r <> char '*' + +machRepCType :: Platform -> CmmType -> SDoc +machRepCType platform ty + | isFloatType ty = machRep_F_CType w + | otherwise = machRep_U_CType platform w + where + w = typeWidth ty machRep_F_CType :: Width -> SDoc machRep_F_CType W32 = text "StgFloat" -- ToDo: correct? machRep_F_CType W64 = text "StgDouble" machRep_F_CType _ = panic "machRep_F_CType" -machRep_U_CType :: Width -> SDoc -machRep_U_CType w - = sdocWithDynFlags $ \dflags -> - case w of - _ | w == wordWidth dflags -> text "W_" +machRep_U_CType :: Platform -> Width -> SDoc +machRep_U_CType platform w + = case w of + _ | w == wordWidth platform -> text "W_" W8 -> text "StgWord8" W16 -> text "StgWord16" W32 -> text "StgWord32" W64 -> text "StgWord64" _ -> panic "machRep_U_CType" -machRep_S_CType :: Width -> SDoc -machRep_S_CType w - = sdocWithDynFlags $ \dflags -> - case w of - _ | w == wordWidth dflags -> text "I_" +machRep_S_CType :: Platform -> Width -> SDoc +machRep_S_CType platform w + = case w of + _ | w == wordWidth platform -> text "I_" W8 -> text "StgInt8" W16 -> text "StgInt16" W32 -> text "StgInt32" @@ -1266,11 +1278,12 @@ floatToWord dflags r writeArray arr 0 (fromRational r) arr' <- castFloatToWord32Array arr w32 <- readArray arr' 0 - return (CmmInt (toInteger w32 `shiftL` wo) (wordWidth dflags)) + return (CmmInt (toInteger w32 `shiftL` wo) (wordWidth platform)) ) - where wo | wordWidth dflags == W64 + where wo | wordWidth platform == W64 , wORDS_BIGENDIAN dflags = 32 | otherwise = 0 + platform = targetPlatform dflags floatPairToWord :: DynFlags -> Rational -> Rational -> CmmLit floatPairToWord dflags r1 r2 @@ -1300,7 +1313,8 @@ doubleToWords dflags r w64 <- readArray arr' 0 return (pprWord64 w64) ) - where targetWidth = wordWidth dflags + where targetWidth = wordWidth platform + platform = targetPlatform dflags targetBE = wORDS_BIGENDIAN dflags pprWord64 w64 | targetWidth == W64 = @@ -1319,15 +1333,15 @@ doubleToWords dflags r -- --------------------------------------------------------------------------- -- Utils -wordShift :: DynFlags -> Int -wordShift dflags = widthInLog (wordWidth dflags) +wordShift :: Platform -> Int +wordShift platform = widthInLog (wordWidth platform) commafy :: [SDoc] -> SDoc commafy xs = hsep $ punctuate comma xs -- Print in C hex format: 0x13fa -pprHexVal :: Integer -> Width -> SDoc -pprHexVal w rep +pprHexVal :: DynFlags -> Integer -> Width -> SDoc +pprHexVal dflags w rep | w < 0 = parens (char '-' <> text "0x" <> intToDoc (-w) <> repsuffix rep) | otherwise = text "0x" <> intToDoc w <> repsuffix rep @@ -1338,7 +1352,7 @@ pprHexVal w rep -- times values are unsigned. This also helps eliminate occasional -- warnings about integer overflow from gcc. - repsuffix W64 = sdocWithDynFlags $ \dflags -> + repsuffix W64 = if cINT_SIZE dflags == 8 then char 'U' else if cLONG_SIZE dflags == 8 then text "UL" else if cLONG_LONG_SIZE dflags == 8 then text "ULL" |