PageRenderTime 26ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/ghc-7.0.4/compiler/cmm/PprC.hs

http://picorec.googlecode.com/
Haskell | 1123 lines | 716 code | 190 blank | 217 comment | 46 complexity | 3d1f7445f8e226894e6095627512bd2c MD5 | raw file
Possible License(s): BSD-3-Clause, BSD-2-Clause
  1. {-# OPTIONS -w #-}
  2. -- The above warning supression flag is a temporary kludge.
  3. -- While working on this module you are encouraged to remove it and fix
  4. -- any warnings in the module. See
  5. -- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
  6. -- for details
  7. -----------------------------------------------------------------------------
  8. --
  9. -- Pretty-printing of Cmm as C, suitable for feeding gcc
  10. --
  11. -- (c) The University of Glasgow 2004-2006
  12. --
  13. -----------------------------------------------------------------------------
  14. --
  15. -- Print Cmm as real C, for -fvia-C
  16. --
  17. -- See wiki:Commentary/Compiler/Backends/PprC
  18. --
  19. -- This is simpler than the old PprAbsC, because Cmm is "macro-expanded"
  20. -- relative to the old AbstractC, and many oddities/decorations have
  21. -- disappeared from the data type.
  22. --
  23. -- ToDo: save/restore volatile registers around calls.
  24. module PprC (
  25. writeCs,
  26. pprStringInCStyle
  27. ) where
  28. #include "HsVersions.h"
  29. -- Cmm stuff
  30. import BlockId
  31. import Cmm
  32. import PprCmm () -- Instances only
  33. import CLabel
  34. import ForeignCall
  35. import ClosureInfo
  36. -- Utils
  37. import DynFlags
  38. import Unique
  39. import UniqSet
  40. import UniqFM
  41. import FastString
  42. import Outputable
  43. import Constants
  44. import BasicTypes
  45. import CLabel
  46. -- The rest
  47. import Data.List
  48. import Data.Bits
  49. import Data.Char
  50. import System.IO
  51. import Data.Map (Map)
  52. import qualified Data.Map as Map
  53. import Data.Word
  54. import Data.Array.ST
  55. import Control.Monad.ST
  56. #if x86_64_TARGET_ARCH
  57. import StaticFlags ( opt_Unregisterised )
  58. #endif
  59. #if defined(alpha_TARGET_ARCH) || defined(mips_TARGET_ARCH) || defined(mipsel_TARGET_ARCH) || defined(arm_TARGET_ARCH)
  60. #define BEWARE_LOAD_STORE_ALIGNMENT
  61. #endif
  62. -- --------------------------------------------------------------------------
  63. -- Top level
  64. pprCs :: DynFlags -> [RawCmm] -> SDoc
  65. pprCs dflags cmms
  66. = pprCode CStyle (vcat $ map (\c -> split_marker $$ pprC c) cmms)
  67. where
  68. split_marker
  69. | dopt Opt_SplitObjs dflags = ptext (sLit "__STG_SPLIT_MARKER")
  70. | otherwise = empty
  71. writeCs :: DynFlags -> Handle -> [RawCmm] -> IO ()
  72. writeCs dflags handle cmms
  73. = printForC handle (pprCs dflags cmms)
  74. -- --------------------------------------------------------------------------
  75. -- Now do some real work
  76. --
  77. -- for fun, we could call cmmToCmm over the tops...
  78. --
  79. pprC :: RawCmm -> SDoc
  80. pprC (Cmm tops) = vcat $ intersperse blankLine $ map pprTop tops
  81. --
  82. -- top level procs
  83. --
  84. pprTop :: RawCmmTop -> SDoc
  85. pprTop (CmmProc info clbl _params (ListGraph blocks)) =
  86. (if not (null info)
  87. then pprDataExterns info $$
  88. pprWordArray (entryLblToInfoLbl clbl) info
  89. else empty) $$
  90. (case blocks of
  91. [] -> empty
  92. -- the first block doesn't get a label:
  93. (BasicBlock _ stmts : rest) -> vcat [
  94. blankLine,
  95. extern_decls,
  96. (if (externallyVisibleCLabel clbl)
  97. then mkFN_ else mkIF_) (pprCLabel clbl) <+> lbrace,
  98. nest 8 temp_decls,
  99. nest 8 mkFB_,
  100. nest 8 (vcat (map pprStmt stmts)) $$
  101. vcat (map pprBBlock rest),
  102. nest 8 mkFE_,
  103. rbrace ]
  104. )
  105. where
  106. (temp_decls, extern_decls) = pprTempAndExternDecls blocks
  107. -- Chunks of static data.
  108. -- We only handle (a) arrays of word-sized things and (b) strings.
  109. pprTop (CmmData _section _ds@[CmmDataLabel lbl, CmmString str]) =
  110. hcat [
  111. pprLocalness lbl, ptext (sLit "char "), pprCLabel lbl,
  112. ptext (sLit "[] = "), pprStringInCStyle str, semi
  113. ]
  114. pprTop (CmmData _section _ds@[CmmDataLabel lbl, CmmUninitialised size]) =
  115. hcat [
  116. pprLocalness lbl, ptext (sLit "char "), pprCLabel lbl,
  117. brackets (int size), semi
  118. ]
  119. pprTop top@(CmmData _section (CmmDataLabel lbl : lits)) =
  120. pprDataExterns lits $$
  121. pprWordArray lbl lits
  122. -- Floating info table for safe a foreign call.
  123. pprTop top@(CmmData _section d@(_ : _))
  124. | CmmDataLabel lbl : lits <- reverse d =
  125. let lits' = reverse lits
  126. in pprDataExterns lits' $$
  127. pprWordArray lbl lits'
  128. -- these shouldn't appear?
  129. pprTop (CmmData _ _) = panic "PprC.pprTop: can't handle this data"
  130. -- --------------------------------------------------------------------------
  131. -- BasicBlocks are self-contained entities: they always end in a jump.
  132. --
  133. -- Like nativeGen/AsmCodeGen, we could probably reorder blocks to turn
  134. -- as many jumps as possible into fall throughs.
  135. --
  136. pprBBlock :: CmmBasicBlock -> SDoc
  137. pprBBlock (BasicBlock lbl stmts) =
  138. if null stmts then
  139. pprTrace "pprC.pprBBlock: curious empty code block for"
  140. (pprBlockId lbl) empty
  141. else
  142. nest 4 (pprBlockId lbl <> colon) $$
  143. nest 8 (vcat (map pprStmt stmts))
  144. -- --------------------------------------------------------------------------
  145. -- Info tables. Just arrays of words.
  146. -- See codeGen/ClosureInfo, and nativeGen/PprMach
  147. pprWordArray :: CLabel -> [CmmStatic] -> SDoc
  148. pprWordArray lbl ds
  149. = hcat [ pprLocalness lbl, ptext (sLit "StgWord")
  150. , space, pprCLabel lbl, ptext (sLit "[] = {") ]
  151. $$ nest 8 (commafy (pprStatics ds))
  152. $$ ptext (sLit "};")
  153. --
  154. -- has to be static, if it isn't globally visible
  155. --
  156. pprLocalness :: CLabel -> SDoc
  157. pprLocalness lbl | not $ externallyVisibleCLabel lbl = ptext (sLit "static ")
  158. | otherwise = empty
  159. -- --------------------------------------------------------------------------
  160. -- Statements.
  161. --
  162. pprStmt :: CmmStmt -> SDoc
  163. pprStmt stmt = case stmt of
  164. CmmNop -> empty
  165. CmmComment s -> empty -- (hang (ptext (sLit "/*")) 3 (ftext s)) $$ ptext (sLit "*/")
  166. -- XXX if the string contains "*/", we need to fix it
  167. -- XXX we probably want to emit these comments when
  168. -- some debugging option is on. They can get quite
  169. -- large.
  170. CmmAssign dest src -> pprAssign dest src
  171. CmmStore dest src
  172. | typeWidth rep == W64 && wordWidth /= W64
  173. -> (if isFloatType rep then ptext (sLit "ASSIGN_DBL")
  174. else ptext (sLit ("ASSIGN_Word64"))) <>
  175. parens (mkP_ <> pprExpr1 dest <> comma <> pprExpr src) <> semi
  176. | otherwise
  177. -> hsep [ pprExpr (CmmLoad dest rep), equals, pprExpr src <> semi ]
  178. where
  179. rep = cmmExprType src
  180. CmmCall (CmmCallee fn cconv) results args safety ret ->
  181. maybe_proto $$
  182. fnCall
  183. where
  184. cast_fn = parens (cCast (pprCFunType (char '*') cconv results args) fn)
  185. real_fun_proto lbl = char ';' <>
  186. pprCFunType (pprCLabel lbl) cconv results args <>
  187. noreturn_attr <> semi
  188. fun_proto lbl = ptext (sLit ";EF_(") <>
  189. pprCLabel lbl <> char ')' <> semi
  190. noreturn_attr = case ret of
  191. CmmNeverReturns -> text "__attribute__ ((noreturn))"
  192. CmmMayReturn -> empty
  193. -- See wiki:Commentary/Compiler/Backends/PprC#Prototypes
  194. (maybe_proto, fnCall) =
  195. case fn of
  196. CmmLit (CmmLabel lbl)
  197. | StdCallConv <- cconv ->
  198. let myCall = pprCall (pprCLabel lbl) cconv results args safety
  199. in (real_fun_proto lbl, myCall)
  200. -- stdcall functions must be declared with
  201. -- a function type, otherwise the C compiler
  202. -- doesn't add the @n suffix to the label. We
  203. -- can't add the @n suffix ourselves, because
  204. -- it isn't valid C.
  205. | CmmNeverReturns <- ret ->
  206. let myCall = pprCall (pprCLabel lbl) cconv results args safety
  207. in (real_fun_proto lbl, myCall)
  208. | not (isMathFun lbl) ->
  209. let myCall = braces (
  210. pprCFunType (char '*' <> text "ghcFunPtr") cconv results args <> semi
  211. $$ text "ghcFunPtr" <+> equals <+> cast_fn <> semi
  212. $$ pprCall (text "ghcFunPtr") cconv results args safety <> semi
  213. )
  214. in (fun_proto lbl, myCall)
  215. _ ->
  216. (empty {- no proto -},
  217. pprCall cast_fn cconv results args safety <> semi)
  218. -- for a dynamic call, no declaration is necessary.
  219. CmmCall (CmmPrim op) results args safety _ret ->
  220. pprCall ppr_fn CCallConv results args safety
  221. where
  222. ppr_fn = pprCallishMachOp_for_C op
  223. CmmBranch ident -> pprBranch ident
  224. CmmCondBranch expr ident -> pprCondBranch expr ident
  225. CmmJump lbl _params -> mkJMP_(pprExpr lbl) <> semi
  226. CmmSwitch arg ids -> pprSwitch arg ids
  227. pprCFunType :: SDoc -> CCallConv -> HintedCmmFormals -> HintedCmmActuals -> SDoc
  228. pprCFunType ppr_fn cconv ress args
  229. = res_type ress <+>
  230. parens (text (ccallConvAttribute cconv) <> ppr_fn) <>
  231. parens (commafy (map arg_type args))
  232. where
  233. res_type [] = ptext (sLit "void")
  234. res_type [CmmHinted one hint] = machRepHintCType (localRegType one) hint
  235. arg_type (CmmHinted expr hint) = machRepHintCType (cmmExprType expr) hint
  236. -- ---------------------------------------------------------------------
  237. -- unconditional branches
  238. pprBranch :: BlockId -> SDoc
  239. pprBranch ident = ptext (sLit "goto") <+> pprBlockId ident <> semi
  240. -- ---------------------------------------------------------------------
  241. -- conditional branches to local labels
  242. pprCondBranch :: CmmExpr -> BlockId -> SDoc
  243. pprCondBranch expr ident
  244. = hsep [ ptext (sLit "if") , parens(pprExpr expr) ,
  245. ptext (sLit "goto") , (pprBlockId ident) <> semi ]
  246. -- ---------------------------------------------------------------------
  247. -- a local table branch
  248. --
  249. -- we find the fall-through cases
  250. --
  251. -- N.B. we remove Nothing's from the list of branches, as they are
  252. -- 'undefined'. However, they may be defined one day, so we better
  253. -- document this behaviour.
  254. --
  255. pprSwitch :: CmmExpr -> [ Maybe BlockId ] -> SDoc
  256. pprSwitch e maybe_ids
  257. = let pairs = [ (ix, ident) | (ix,Just ident) <- zip [0..] maybe_ids ]
  258. pairs2 = [ (map fst as, snd (head as)) | as <- groupBy sndEq pairs ]
  259. in
  260. (hang (ptext (sLit "switch") <+> parens ( pprExpr e ) <+> lbrace)
  261. 4 (vcat ( map caseify pairs2 )))
  262. $$ rbrace
  263. where
  264. sndEq (_,x) (_,y) = x == y
  265. -- fall through case
  266. caseify (ix:ixs, ident) = vcat (map do_fallthrough ixs) $$ final_branch ix
  267. where
  268. do_fallthrough ix =
  269. hsep [ ptext (sLit "case") , pprHexVal ix wordWidth <> colon ,
  270. ptext (sLit "/* fall through */") ]
  271. final_branch ix =
  272. hsep [ ptext (sLit "case") , pprHexVal ix wordWidth <> colon ,
  273. ptext (sLit "goto") , (pprBlockId ident) <> semi ]
  274. -- ---------------------------------------------------------------------
  275. -- Expressions.
  276. --
  277. -- C Types: the invariant is that the C expression generated by
  278. --
  279. -- pprExpr e
  280. --
  281. -- has a type in C which is also given by
  282. --
  283. -- machRepCType (cmmExprType e)
  284. --
  285. -- (similar invariants apply to the rest of the pretty printer).
  286. pprExpr :: CmmExpr -> SDoc
  287. pprExpr e = case e of
  288. CmmLit lit -> pprLit lit
  289. CmmLoad e ty -> pprLoad e ty
  290. CmmReg reg -> pprCastReg reg
  291. CmmRegOff reg 0 -> pprCastReg reg
  292. CmmRegOff reg i
  293. | i > 0 -> pprRegOff (char '+') i
  294. | otherwise -> pprRegOff (char '-') (-i)
  295. where
  296. pprRegOff op i' = pprCastReg reg <> op <> int i'
  297. CmmMachOp mop args -> pprMachOpApp mop args
  298. pprLoad :: CmmExpr -> CmmType -> SDoc
  299. pprLoad e ty
  300. | width == W64, wordWidth /= W64
  301. = (if isFloatType ty then ptext (sLit "PK_DBL")
  302. else ptext (sLit "PK_Word64"))
  303. <> parens (mkP_ <> pprExpr1 e)
  304. | otherwise
  305. = case e of
  306. CmmReg r | isPtrReg r && width == wordWidth && not (isFloatType ty)
  307. -> char '*' <> pprAsPtrReg r
  308. CmmRegOff r 0 | isPtrReg r && width == wordWidth && not (isFloatType ty)
  309. -> char '*' <> pprAsPtrReg r
  310. CmmRegOff r off | isPtrReg r && width == wordWidth
  311. , off `rem` wORD_SIZE == 0 && not (isFloatType ty)
  312. -- ToDo: check that the offset is a word multiple?
  313. -- (For tagging to work, I had to avoid unaligned loads. --ARY)
  314. -> pprAsPtrReg r <> brackets (ppr (off `shiftR` wordShift))
  315. _other -> cLoad e ty
  316. where
  317. width = typeWidth ty
  318. pprExpr1 :: CmmExpr -> SDoc
  319. pprExpr1 (CmmLit lit) = pprLit1 lit
  320. pprExpr1 e@(CmmReg _reg) = pprExpr e
  321. pprExpr1 other = parens (pprExpr other)
  322. -- --------------------------------------------------------------------------
  323. -- MachOp applications
  324. pprMachOpApp :: MachOp -> [CmmExpr] -> SDoc
  325. pprMachOpApp op args
  326. | isMulMayOfloOp op
  327. = ptext (sLit "mulIntMayOflo") <> parens (commafy (map pprExpr args))
  328. where isMulMayOfloOp (MO_U_MulMayOflo _) = True
  329. isMulMayOfloOp (MO_S_MulMayOflo _) = True
  330. isMulMayOfloOp _ = False
  331. pprMachOpApp mop args
  332. | Just ty <- machOpNeedsCast mop
  333. = ty <> parens (pprMachOpApp' mop args)
  334. | otherwise
  335. = pprMachOpApp' mop args
  336. -- Comparisons in C have type 'int', but we want type W_ (this is what
  337. -- resultRepOfMachOp says). The other C operations inherit their type
  338. -- from their operands, so no casting is required.
  339. machOpNeedsCast :: MachOp -> Maybe SDoc
  340. machOpNeedsCast mop
  341. | isComparisonMachOp mop = Just mkW_
  342. | otherwise = Nothing
  343. pprMachOpApp' mop args
  344. = case args of
  345. -- dyadic
  346. [x,y] -> pprArg x <+> pprMachOp_for_C mop <+> pprArg y
  347. -- unary
  348. [x] -> pprMachOp_for_C mop <> parens (pprArg x)
  349. _ -> panic "PprC.pprMachOp : machop with wrong number of args"
  350. where
  351. -- Cast needed for signed integer ops
  352. pprArg e | signedOp mop = cCast (machRep_S_CType (typeWidth (cmmExprType e))) e
  353. | needsFCasts mop = cCast (machRep_F_CType (typeWidth (cmmExprType e))) e
  354. | otherwise = pprExpr1 e
  355. needsFCasts (MO_F_Eq _) = False
  356. needsFCasts (MO_F_Ne _) = False
  357. needsFCasts (MO_F_Neg _) = True
  358. needsFCasts (MO_F_Quot _) = True
  359. needsFCasts mop = floatComparison mop
  360. -- --------------------------------------------------------------------------
  361. -- Literals
  362. pprLit :: CmmLit -> SDoc
  363. pprLit lit = case lit of
  364. CmmInt i rep -> pprHexVal i rep
  365. CmmFloat f w -> parens (machRep_F_CType w) <> str
  366. where d = fromRational f :: Double
  367. str | isInfinite d && d < 0 = ptext (sLit "-INFINITY")
  368. | isInfinite d = ptext (sLit "INFINITY")
  369. | isNaN d = ptext (sLit "NAN")
  370. | otherwise = text (show d)
  371. -- these constants come from <math.h>
  372. -- see #1861
  373. CmmBlock bid -> mkW_ <> pprCLabelAddr (infoTblLbl bid)
  374. CmmHighStackMark -> panic "PprC printing high stack mark"
  375. CmmLabel clbl -> mkW_ <> pprCLabelAddr clbl
  376. CmmLabelOff clbl i -> mkW_ <> pprCLabelAddr clbl <> char '+' <> int i
  377. CmmLabelDiffOff clbl1 clbl2 i
  378. -- WARNING:
  379. -- * the lit must occur in the info table clbl2
  380. -- * clbl1 must be an SRT, a slow entry point or a large bitmap
  381. -- The Mangler is expected to convert any reference to an SRT,
  382. -- a slow entry point or a large bitmap
  383. -- from an info table to an offset.
  384. -> mkW_ <> pprCLabelAddr clbl1 <> char '+' <> int i
  385. pprCLabelAddr lbl = char '&' <> pprCLabel lbl
  386. pprLit1 :: CmmLit -> SDoc
  387. pprLit1 lit@(CmmLabelOff _ _) = parens (pprLit lit)
  388. pprLit1 lit@(CmmLabelDiffOff _ _ _) = parens (pprLit lit)
  389. pprLit1 lit@(CmmFloat _ _) = parens (pprLit lit)
  390. pprLit1 other = pprLit other
  391. -- ---------------------------------------------------------------------------
  392. -- Static data
  393. pprStatics :: [CmmStatic] -> [SDoc]
  394. pprStatics [] = []
  395. pprStatics (CmmStaticLit (CmmFloat f W32) : rest)
  396. -- floats are padded to a word, see #1852
  397. | wORD_SIZE == 8, CmmStaticLit (CmmInt 0 W32) : rest' <- rest
  398. = pprLit1 (floatToWord f) : pprStatics rest'
  399. | wORD_SIZE == 4
  400. = pprLit1 (floatToWord f) : pprStatics rest
  401. | otherwise
  402. = pprPanic "pprStatics: float" (vcat (map (\(CmmStaticLit l) -> ppr (cmmLitType l)) rest))
  403. pprStatics (CmmStaticLit (CmmFloat f W64) : rest)
  404. = map pprLit1 (doubleToWords f) ++ pprStatics rest
  405. pprStatics (CmmStaticLit (CmmInt i W64) : rest)
  406. | wordWidth == W32
  407. #ifdef WORDS_BIGENDIAN
  408. = pprStatics (CmmStaticLit (CmmInt q W32) :
  409. CmmStaticLit (CmmInt r W32) : rest)
  410. #else
  411. = pprStatics (CmmStaticLit (CmmInt r W32) :
  412. CmmStaticLit (CmmInt q W32) : rest)
  413. #endif
  414. where r = i .&. 0xffffffff
  415. q = i `shiftR` 32
  416. pprStatics (CmmStaticLit (CmmInt i w) : rest)
  417. | w /= wordWidth
  418. = panic "pprStatics: cannot emit a non-word-sized static literal"
  419. pprStatics (CmmStaticLit lit : rest)
  420. = pprLit1 lit : pprStatics rest
  421. pprStatics (other : rest)
  422. = pprPanic "pprWord" (pprStatic other)
  423. pprStatic :: CmmStatic -> SDoc
  424. pprStatic s = case s of
  425. CmmStaticLit lit -> nest 4 (pprLit lit)
  426. CmmAlign i -> nest 4 (ptext (sLit "/* align */") <+> int i)
  427. CmmDataLabel clbl -> pprCLabel clbl <> colon
  428. CmmUninitialised i -> nest 4 (mkC_ <> brackets (int i))
  429. -- these should be inlined, like the old .hc
  430. CmmString s' -> nest 4 (mkW_ <> parens(pprStringInCStyle s'))
  431. -- ---------------------------------------------------------------------------
  432. -- Block Ids
  433. pprBlockId :: BlockId -> SDoc
  434. pprBlockId b = char '_' <> ppr (getUnique b)
  435. -- --------------------------------------------------------------------------
  436. -- Print a MachOp in a way suitable for emitting via C.
  437. --
  438. pprMachOp_for_C :: MachOp -> SDoc
  439. pprMachOp_for_C mop = case mop of
  440. -- Integer operations
  441. MO_Add _ -> char '+'
  442. MO_Sub _ -> char '-'
  443. MO_Eq _ -> ptext (sLit "==")
  444. MO_Ne _ -> ptext (sLit "!=")
  445. MO_Mul _ -> char '*'
  446. MO_S_Quot _ -> char '/'
  447. MO_S_Rem _ -> char '%'
  448. MO_S_Neg _ -> char '-'
  449. MO_U_Quot _ -> char '/'
  450. MO_U_Rem _ -> char '%'
  451. -- & Floating-point operations
  452. MO_F_Add _ -> char '+'
  453. MO_F_Sub _ -> char '-'
  454. MO_F_Neg _ -> char '-'
  455. MO_F_Mul _ -> char '*'
  456. MO_F_Quot _ -> char '/'
  457. -- Signed comparisons
  458. MO_S_Ge _ -> ptext (sLit ">=")
  459. MO_S_Le _ -> ptext (sLit "<=")
  460. MO_S_Gt _ -> char '>'
  461. MO_S_Lt _ -> char '<'
  462. -- & Unsigned comparisons
  463. MO_U_Ge _ -> ptext (sLit ">=")
  464. MO_U_Le _ -> ptext (sLit "<=")
  465. MO_U_Gt _ -> char '>'
  466. MO_U_Lt _ -> char '<'
  467. -- & Floating-point comparisons
  468. MO_F_Eq _ -> ptext (sLit "==")
  469. MO_F_Ne _ -> ptext (sLit "!=")
  470. MO_F_Ge _ -> ptext (sLit ">=")
  471. MO_F_Le _ -> ptext (sLit "<=")
  472. MO_F_Gt _ -> char '>'
  473. MO_F_Lt _ -> char '<'
  474. -- Bitwise operations. Not all of these may be supported at all
  475. -- sizes, and only integral MachReps are valid.
  476. MO_And _ -> char '&'
  477. MO_Or _ -> char '|'
  478. MO_Xor _ -> char '^'
  479. MO_Not _ -> char '~'
  480. MO_Shl _ -> ptext (sLit "<<")
  481. MO_U_Shr _ -> ptext (sLit ">>") -- unsigned shift right
  482. MO_S_Shr _ -> ptext (sLit ">>") -- signed shift right
  483. -- Conversions. Some of these will be NOPs, but never those that convert
  484. -- between ints and floats.
  485. -- Floating-point conversions use the signed variant.
  486. -- We won't know to generate (void*) casts here, but maybe from
  487. -- context elsewhere
  488. -- noop casts
  489. MO_UU_Conv from to | from == to -> empty
  490. MO_UU_Conv _from to -> parens (machRep_U_CType to)
  491. MO_SS_Conv from to | from == to -> empty
  492. MO_SS_Conv _from to -> parens (machRep_S_CType to)
  493. -- TEMPORARY: the old code didn't check this case, so let's leave it out
  494. -- to facilitate comparisons against the old output code.
  495. --MO_FF_Conv from to | from == to -> empty
  496. MO_FF_Conv _from to -> parens (machRep_F_CType to)
  497. MO_SF_Conv _from to -> parens (machRep_F_CType to)
  498. MO_FS_Conv _from to -> parens (machRep_S_CType to)
  499. _ -> pprTrace "offending mop" (ptext $ sLit $ show mop) $
  500. panic "PprC.pprMachOp_for_C: unknown machop"
  501. signedOp :: MachOp -> Bool -- Argument type(s) are signed ints
  502. signedOp (MO_S_Quot _) = True
  503. signedOp (MO_S_Rem _) = True
  504. signedOp (MO_S_Neg _) = True
  505. signedOp (MO_S_Ge _) = True
  506. signedOp (MO_S_Le _) = True
  507. signedOp (MO_S_Gt _) = True
  508. signedOp (MO_S_Lt _) = True
  509. signedOp (MO_S_Shr _) = True
  510. signedOp (MO_SS_Conv _ _) = True
  511. signedOp (MO_SF_Conv _ _) = True
  512. signedOp _ = False
  513. floatComparison :: MachOp -> Bool -- comparison between float args
  514. floatComparison (MO_F_Eq _) = True
  515. floatComparison (MO_F_Ne _) = True
  516. floatComparison (MO_F_Ge _) = True
  517. floatComparison (MO_F_Le _) = True
  518. floatComparison (MO_F_Gt _) = True
  519. floatComparison (MO_F_Lt _) = True
  520. floatComparison _ = False
  521. -- ---------------------------------------------------------------------
  522. -- tend to be implemented by foreign calls
  523. pprCallishMachOp_for_C :: CallishMachOp -> SDoc
  524. pprCallishMachOp_for_C mop
  525. = case mop of
  526. MO_F64_Pwr -> ptext (sLit "pow")
  527. MO_F64_Sin -> ptext (sLit "sin")
  528. MO_F64_Cos -> ptext (sLit "cos")
  529. MO_F64_Tan -> ptext (sLit "tan")
  530. MO_F64_Sinh -> ptext (sLit "sinh")
  531. MO_F64_Cosh -> ptext (sLit "cosh")
  532. MO_F64_Tanh -> ptext (sLit "tanh")
  533. MO_F64_Asin -> ptext (sLit "asin")
  534. MO_F64_Acos -> ptext (sLit "acos")
  535. MO_F64_Atan -> ptext (sLit "atan")
  536. MO_F64_Log -> ptext (sLit "log")
  537. MO_F64_Exp -> ptext (sLit "exp")
  538. MO_F64_Sqrt -> ptext (sLit "sqrt")
  539. MO_F32_Pwr -> ptext (sLit "powf")
  540. MO_F32_Sin -> ptext (sLit "sinf")
  541. MO_F32_Cos -> ptext (sLit "cosf")
  542. MO_F32_Tan -> ptext (sLit "tanf")
  543. MO_F32_Sinh -> ptext (sLit "sinhf")
  544. MO_F32_Cosh -> ptext (sLit "coshf")
  545. MO_F32_Tanh -> ptext (sLit "tanhf")
  546. MO_F32_Asin -> ptext (sLit "asinf")
  547. MO_F32_Acos -> ptext (sLit "acosf")
  548. MO_F32_Atan -> ptext (sLit "atanf")
  549. MO_F32_Log -> ptext (sLit "logf")
  550. MO_F32_Exp -> ptext (sLit "expf")
  551. MO_F32_Sqrt -> ptext (sLit "sqrtf")
  552. MO_WriteBarrier -> ptext (sLit "write_barrier")
  553. -- ---------------------------------------------------------------------
  554. -- Useful #defines
  555. --
  556. mkJMP_, mkFN_, mkIF_ :: SDoc -> SDoc
  557. mkJMP_ i = ptext (sLit "JMP_") <> parens i
  558. mkFN_ i = ptext (sLit "FN_") <> parens i -- externally visible function
  559. mkIF_ i = ptext (sLit "IF_") <> parens i -- locally visible
  560. mkFB_, mkFE_ :: SDoc
  561. mkFB_ = ptext (sLit "FB_") -- function code begin
  562. mkFE_ = ptext (sLit "FE_") -- function code end
  563. -- from includes/Stg.h
  564. --
  565. mkC_,mkW_,mkP_ :: SDoc
  566. mkC_ = ptext (sLit "(C_)") -- StgChar
  567. mkW_ = ptext (sLit "(W_)") -- StgWord
  568. mkP_ = ptext (sLit "(P_)") -- StgWord*
  569. -- ---------------------------------------------------------------------
  570. --
  571. -- Assignments
  572. --
  573. -- Generating assignments is what we're all about, here
  574. --
  575. pprAssign :: CmmReg -> CmmExpr -> SDoc
  576. -- dest is a reg, rhs is a reg
  577. pprAssign r1 (CmmReg r2)
  578. | isPtrReg r1 && isPtrReg r2
  579. = hcat [ pprAsPtrReg r1, equals, pprAsPtrReg r2, semi ]
  580. -- dest is a reg, rhs is a CmmRegOff
  581. pprAssign r1 (CmmRegOff r2 off)
  582. | isPtrReg r1 && isPtrReg r2 && (off `rem` wORD_SIZE == 0)
  583. = hcat [ pprAsPtrReg r1, equals, pprAsPtrReg r2, op, int off', semi ]
  584. where
  585. off1 = off `shiftR` wordShift
  586. (op,off') | off >= 0 = (char '+', off1)
  587. | otherwise = (char '-', -off1)
  588. -- dest is a reg, rhs is anything.
  589. -- We can't cast the lvalue, so we have to cast the rhs if necessary. Casting
  590. -- the lvalue elicits a warning from new GCC versions (3.4+).
  591. pprAssign r1 r2
  592. | isFixedPtrReg r1 = mkAssign (mkP_ <> pprExpr1 r2)
  593. | Just ty <- strangeRegType r1 = mkAssign (parens ty <> pprExpr1 r2)
  594. | otherwise = mkAssign (pprExpr r2)
  595. where mkAssign x = if r1 == CmmGlobal BaseReg
  596. then ptext (sLit "ASSIGN_BaseReg") <> parens x <> semi
  597. else pprReg r1 <> ptext (sLit " = ") <> x <> semi
  598. -- ---------------------------------------------------------------------
  599. -- Registers
  600. pprCastReg reg
  601. | isStrangeTypeReg reg = mkW_ <> pprReg reg
  602. | otherwise = pprReg reg
  603. -- True if (pprReg reg) will give an expression with type StgPtr. We
  604. -- need to take care with pointer arithmetic on registers with type
  605. -- StgPtr.
  606. isFixedPtrReg :: CmmReg -> Bool
  607. isFixedPtrReg (CmmLocal _) = False
  608. isFixedPtrReg (CmmGlobal r) = isFixedPtrGlobalReg r
  609. -- True if (pprAsPtrReg reg) will give an expression with type StgPtr
  610. -- JD: THIS IS HORRIBLE AND SHOULD BE RENAMED, AT THE VERY LEAST.
  611. -- THE GARBAGE WITH THE VNonGcPtr HELPS MATCH THE OLD CODE GENERATOR'S OUTPUT;
  612. -- I'M NOT SURE IF IT SHOULD REALLY STAY THAT WAY.
  613. isPtrReg :: CmmReg -> Bool
  614. isPtrReg (CmmLocal _) = False
  615. isPtrReg (CmmGlobal (VanillaReg n VGcPtr)) = True -- if we print via pprAsPtrReg
  616. isPtrReg (CmmGlobal (VanillaReg n VNonGcPtr)) = False --if we print via pprAsPtrReg
  617. isPtrReg (CmmGlobal reg) = isFixedPtrGlobalReg reg
  618. -- True if this global reg has type StgPtr
  619. isFixedPtrGlobalReg :: GlobalReg -> Bool
  620. isFixedPtrGlobalReg Sp = True
  621. isFixedPtrGlobalReg Hp = True
  622. isFixedPtrGlobalReg HpLim = True
  623. isFixedPtrGlobalReg SpLim = True
  624. isFixedPtrGlobalReg _ = False
  625. -- True if in C this register doesn't have the type given by
  626. -- (machRepCType (cmmRegType reg)), so it has to be cast.
  627. isStrangeTypeReg :: CmmReg -> Bool
  628. isStrangeTypeReg (CmmLocal _) = False
  629. isStrangeTypeReg (CmmGlobal g) = isStrangeTypeGlobal g
  630. isStrangeTypeGlobal :: GlobalReg -> Bool
  631. isStrangeTypeGlobal CurrentTSO = True
  632. isStrangeTypeGlobal CurrentNursery = True
  633. isStrangeTypeGlobal BaseReg = True
  634. isStrangeTypeGlobal r = isFixedPtrGlobalReg r
  635. strangeRegType :: CmmReg -> Maybe SDoc
  636. strangeRegType (CmmGlobal CurrentTSO) = Just (ptext (sLit "struct StgTSO_ *"))
  637. strangeRegType (CmmGlobal CurrentNursery) = Just (ptext (sLit "struct bdescr_ *"))
  638. strangeRegType (CmmGlobal BaseReg) = Just (ptext (sLit "struct StgRegTable_ *"))
  639. strangeRegType _ = Nothing
  640. -- pprReg just prints the register name.
  641. --
  642. pprReg :: CmmReg -> SDoc
  643. pprReg r = case r of
  644. CmmLocal local -> pprLocalReg local
  645. CmmGlobal global -> pprGlobalReg global
  646. pprAsPtrReg :: CmmReg -> SDoc
  647. pprAsPtrReg (CmmGlobal (VanillaReg n gcp))
  648. = WARN( gcp /= VGcPtr, ppr n ) char 'R' <> int n <> ptext (sLit ".p")
  649. pprAsPtrReg other_reg = pprReg other_reg
  650. pprGlobalReg :: GlobalReg -> SDoc
  651. pprGlobalReg gr = case gr of
  652. VanillaReg n _ -> char 'R' <> int n <> ptext (sLit ".w")
  653. -- pprGlobalReg prints a VanillaReg as a .w regardless
  654. -- Example: R1.w = R1.w & (-0x8UL);
  655. -- JMP_(*R1.p);
  656. FloatReg n -> char 'F' <> int n
  657. DoubleReg n -> char 'D' <> int n
  658. LongReg n -> char 'L' <> int n
  659. Sp -> ptext (sLit "Sp")
  660. SpLim -> ptext (sLit "SpLim")
  661. Hp -> ptext (sLit "Hp")
  662. HpLim -> ptext (sLit "HpLim")
  663. CurrentTSO -> ptext (sLit "CurrentTSO")
  664. CurrentNursery -> ptext (sLit "CurrentNursery")
  665. HpAlloc -> ptext (sLit "HpAlloc")
  666. BaseReg -> ptext (sLit "BaseReg")
  667. EagerBlackholeInfo -> ptext (sLit "stg_EAGER_BLACKHOLE_info")
  668. GCEnter1 -> ptext (sLit "stg_gc_enter_1")
  669. GCFun -> ptext (sLit "stg_gc_fun")
  670. pprLocalReg :: LocalReg -> SDoc
  671. pprLocalReg (LocalReg uniq _) = char '_' <> ppr uniq
  672. -- -----------------------------------------------------------------------------
  673. -- Foreign Calls
  674. pprCall :: SDoc -> CCallConv -> HintedCmmFormals -> HintedCmmActuals -> CmmSafety
  675. -> SDoc
  676. pprCall ppr_fn cconv results args _
  677. | not (is_cish cconv)
  678. = panic "pprCall: unknown calling convention"
  679. | otherwise
  680. =
  681. #if x86_64_TARGET_ARCH
  682. -- HACK around gcc optimisations.
  683. -- x86_64 needs a __DISCARD__() here, to create a barrier between
  684. -- putting the arguments into temporaries and passing the arguments
  685. -- to the callee, because the argument expressions may refer to
  686. -- machine registers that are also used for passing arguments in the
  687. -- C calling convention.
  688. (if (not opt_Unregisterised)
  689. then ptext (sLit "__DISCARD__();")
  690. else empty) $$
  691. #endif
  692. ppr_assign results (ppr_fn <> parens (commafy (map pprArg args))) <> semi
  693. where
  694. ppr_assign [] rhs = rhs
  695. ppr_assign [CmmHinted one hint] rhs
  696. = pprLocalReg one <> ptext (sLit " = ")
  697. <> pprUnHint hint (localRegType one) <> rhs
  698. ppr_assign _other _rhs = panic "pprCall: multiple results"
  699. pprArg (CmmHinted expr AddrHint)
  700. = cCast (ptext (sLit "void *")) expr
  701. -- see comment by machRepHintCType below
  702. pprArg (CmmHinted expr SignedHint)
  703. = cCast (machRep_S_CType $ typeWidth $ cmmExprType expr) expr
  704. pprArg (CmmHinted expr _other)
  705. = pprExpr expr
  706. pprUnHint AddrHint rep = parens (machRepCType rep)
  707. pprUnHint SignedHint rep = parens (machRepCType rep)
  708. pprUnHint _ _ = empty
  709. pprGlobalRegName :: GlobalReg -> SDoc
  710. pprGlobalRegName gr = case gr of
  711. VanillaReg n _ -> char 'R' <> int n -- without the .w suffix
  712. _ -> pprGlobalReg gr
  713. -- Currently we only have these two calling conventions, but this might
  714. -- change in the future...
  715. is_cish CCallConv = True
  716. is_cish StdCallConv = True
  717. -- ---------------------------------------------------------------------
  718. -- Find and print local and external declarations for a list of
  719. -- Cmm statements.
  720. --
  721. pprTempAndExternDecls :: [CmmBasicBlock] -> (SDoc{-temps-}, SDoc{-externs-})
  722. pprTempAndExternDecls stmts
  723. = (vcat (map pprTempDecl (uniqSetToList temps)),
  724. vcat (map (pprExternDecl False{-ToDo-}) (Map.keys lbls)))
  725. where (temps, lbls) = runTE (mapM_ te_BB stmts)
  726. pprDataExterns :: [CmmStatic] -> SDoc
  727. pprDataExterns statics
  728. = vcat (map (pprExternDecl False{-ToDo-}) (Map.keys lbls))
  729. where (_, lbls) = runTE (mapM_ te_Static statics)
  730. pprTempDecl :: LocalReg -> SDoc
  731. pprTempDecl l@(LocalReg _ rep)
  732. = hcat [ machRepCType rep, space, pprLocalReg l, semi ]
  733. pprExternDecl :: Bool -> CLabel -> SDoc
  734. pprExternDecl in_srt lbl
  735. -- do not print anything for "known external" things
  736. | not (needsCDecl lbl) = empty
  737. | Just sz <- foreignLabelStdcallInfo lbl = stdcall_decl sz
  738. | otherwise =
  739. hcat [ visibility, label_type lbl,
  740. lparen, pprCLabel lbl, text ");" ]
  741. where
  742. label_type lbl | isCFunctionLabel lbl = ptext (sLit "F_")
  743. | otherwise = ptext (sLit "I_")
  744. visibility
  745. | externallyVisibleCLabel lbl = char 'E'
  746. | otherwise = char 'I'
  747. -- If the label we want to refer to is a stdcall function (on Windows) then
  748. -- we must generate an appropriate prototype for it, so that the C compiler will
  749. -- add the @n suffix to the label (#2276)
  750. stdcall_decl sz =
  751. ptext (sLit "extern __attribute__((stdcall)) void ") <> pprCLabel lbl
  752. <> parens (commafy (replicate (sz `quot` wORD_SIZE) (machRep_U_CType wordWidth)))
  753. <> semi
  754. type TEState = (UniqSet LocalReg, Map CLabel ())
  755. newtype TE a = TE { unTE :: TEState -> (a, TEState) }
  756. instance Monad TE where
  757. TE m >>= k = TE $ \s -> case m s of (a, s') -> unTE (k a) s'
  758. return a = TE $ \s -> (a, s)
  759. te_lbl :: CLabel -> TE ()
  760. te_lbl lbl = TE $ \(temps,lbls) -> ((), (temps, Map.insert lbl () lbls))
  761. te_temp :: LocalReg -> TE ()
  762. te_temp r = TE $ \(temps,lbls) -> ((), (addOneToUniqSet temps r, lbls))
  763. runTE :: TE () -> TEState
  764. runTE (TE m) = snd (m (emptyUniqSet, Map.empty))
  765. te_Static :: CmmStatic -> TE ()
  766. te_Static (CmmStaticLit lit) = te_Lit lit
  767. te_Static _ = return ()
  768. te_BB :: CmmBasicBlock -> TE ()
  769. te_BB (BasicBlock _ ss) = mapM_ te_Stmt ss
  770. te_Lit :: CmmLit -> TE ()
  771. te_Lit (CmmLabel l) = te_lbl l
  772. te_Lit (CmmLabelOff l _) = te_lbl l
  773. te_Lit (CmmLabelDiffOff l1 l2 _) = te_lbl l1
  774. te_Lit _ = return ()
  775. te_Stmt :: CmmStmt -> TE ()
  776. te_Stmt (CmmAssign r e) = te_Reg r >> te_Expr e
  777. te_Stmt (CmmStore l r) = te_Expr l >> te_Expr r
  778. te_Stmt (CmmCall _ rs es _ _) = mapM_ (te_temp.hintlessCmm) rs >>
  779. mapM_ (te_Expr.hintlessCmm) es
  780. te_Stmt (CmmCondBranch e _) = te_Expr e
  781. te_Stmt (CmmSwitch e _) = te_Expr e
  782. te_Stmt (CmmJump e _) = te_Expr e
  783. te_Stmt _ = return ()
  784. te_Expr :: CmmExpr -> TE ()
  785. te_Expr (CmmLit lit) = te_Lit lit
  786. te_Expr (CmmLoad e _) = te_Expr e
  787. te_Expr (CmmReg r) = te_Reg r
  788. te_Expr (CmmMachOp _ es) = mapM_ te_Expr es
  789. te_Expr (CmmRegOff r _) = te_Reg r
  790. te_Reg :: CmmReg -> TE ()
  791. te_Reg (CmmLocal l) = te_temp l
  792. te_Reg _ = return ()
  793. -- ---------------------------------------------------------------------
  794. -- C types for MachReps
  795. cCast :: SDoc -> CmmExpr -> SDoc
  796. cCast ty expr = parens ty <> pprExpr1 expr
  797. cLoad :: CmmExpr -> CmmType -> SDoc
  798. #ifdef BEWARE_LOAD_STORE_ALIGNMENT
  799. cLoad expr rep =
  800. let decl = machRepCType rep <+> ptext (sLit "x") <> semi
  801. struct = ptext (sLit "struct") <+> braces (decl)
  802. packed_attr = ptext (sLit "__attribute__((packed))")
  803. cast = parens (struct <+> packed_attr <> char '*')
  804. in parens (cast <+> pprExpr1 expr) <> ptext (sLit "->x")
  805. #else
  806. cLoad expr rep = char '*' <> parens (cCast (machRepPtrCType rep) expr)
  807. #endif
  808. isCmmWordType :: CmmType -> Bool
  809. -- True of GcPtrReg/NonGcReg of native word size
  810. isCmmWordType ty = not (isFloatType ty)
  811. && typeWidth ty == wordWidth
  812. -- This is for finding the types of foreign call arguments. For a pointer
  813. -- argument, we always cast the argument to (void *), to avoid warnings from
  814. -- the C compiler.
  815. machRepHintCType :: CmmType -> ForeignHint -> SDoc
  816. machRepHintCType rep AddrHint = ptext (sLit "void *")
  817. machRepHintCType rep SignedHint = machRep_S_CType (typeWidth rep)
  818. machRepHintCType rep _other = machRepCType rep
  819. machRepPtrCType :: CmmType -> SDoc
  820. machRepPtrCType r | isCmmWordType r = ptext (sLit "P_")
  821. | otherwise = machRepCType r <> char '*'
  822. machRepCType :: CmmType -> SDoc
  823. machRepCType ty | isFloatType ty = machRep_F_CType w
  824. | otherwise = machRep_U_CType w
  825. where
  826. w = typeWidth ty
  827. machRep_F_CType :: Width -> SDoc
  828. machRep_F_CType W32 = ptext (sLit "StgFloat") -- ToDo: correct?
  829. machRep_F_CType W64 = ptext (sLit "StgDouble")
  830. machRep_F_CType _ = panic "machRep_F_CType"
  831. machRep_U_CType :: Width -> SDoc
  832. machRep_U_CType w | w == wordWidth = ptext (sLit "W_")
  833. machRep_U_CType W8 = ptext (sLit "StgWord8")
  834. machRep_U_CType W16 = ptext (sLit "StgWord16")
  835. machRep_U_CType W32 = ptext (sLit "StgWord32")
  836. machRep_U_CType W64 = ptext (sLit "StgWord64")
  837. machRep_U_CType _ = panic "machRep_U_CType"
  838. machRep_S_CType :: Width -> SDoc
  839. machRep_S_CType w | w == wordWidth = ptext (sLit "I_")
  840. machRep_S_CType W8 = ptext (sLit "StgInt8")
  841. machRep_S_CType W16 = ptext (sLit "StgInt16")
  842. machRep_S_CType W32 = ptext (sLit "StgInt32")
  843. machRep_S_CType W64 = ptext (sLit "StgInt64")
  844. machRep_S_CType _ = panic "machRep_S_CType"
  845. -- ---------------------------------------------------------------------
  846. -- print strings as valid C strings
  847. pprStringInCStyle :: [Word8] -> SDoc
  848. pprStringInCStyle s = doubleQuotes (text (concatMap charToC s))
  849. charToC :: Word8 -> String
  850. charToC w =
  851. case chr (fromIntegral w) of
  852. '\"' -> "\\\""
  853. '\'' -> "\\\'"
  854. '\\' -> "\\\\"
  855. c | c >= ' ' && c <= '~' -> [c]
  856. | otherwise -> ['\\',
  857. chr (ord '0' + ord c `div` 64),
  858. chr (ord '0' + ord c `div` 8 `mod` 8),
  859. chr (ord '0' + ord c `mod` 8)]
  860. -- ---------------------------------------------------------------------------
  861. -- Initialising static objects with floating-point numbers. We can't
  862. -- just emit the floating point number, because C will cast it to an int
  863. -- by rounding it. We want the actual bit-representation of the float.
  864. -- This is a hack to turn the floating point numbers into ints that we
  865. -- can safely initialise to static locations.
  866. big_doubles
  867. | widthInBytes W64 == 2 * wORD_SIZE = True
  868. | widthInBytes W64 == wORD_SIZE = False
  869. | otherwise = panic "big_doubles"
  870. castFloatToIntArray :: STUArray s Int Float -> ST s (STUArray s Int Int)
  871. castFloatToIntArray = castSTUArray
  872. castDoubleToIntArray :: STUArray s Int Double -> ST s (STUArray s Int Int)
  873. castDoubleToIntArray = castSTUArray
  874. -- floats are always 1 word
  875. floatToWord :: Rational -> CmmLit
  876. floatToWord r
  877. = runST (do
  878. arr <- newArray_ ((0::Int),0)
  879. writeArray arr 0 (fromRational r)
  880. arr' <- castFloatToIntArray arr
  881. i <- readArray arr' 0
  882. return (CmmInt (toInteger i) wordWidth)
  883. )
  884. doubleToWords :: Rational -> [CmmLit]
  885. doubleToWords r
  886. | big_doubles -- doubles are 2 words
  887. = runST (do
  888. arr <- newArray_ ((0::Int),1)
  889. writeArray arr 0 (fromRational r)
  890. arr' <- castDoubleToIntArray arr
  891. i1 <- readArray arr' 0
  892. i2 <- readArray arr' 1
  893. return [ CmmInt (toInteger i1) wordWidth
  894. , CmmInt (toInteger i2) wordWidth
  895. ]
  896. )
  897. | otherwise -- doubles are 1 word
  898. = runST (do
  899. arr <- newArray_ ((0::Int),0)
  900. writeArray arr 0 (fromRational r)
  901. arr' <- castDoubleToIntArray arr
  902. i <- readArray arr' 0
  903. return [ CmmInt (toInteger i) wordWidth ]
  904. )
  905. -- ---------------------------------------------------------------------------
  906. -- Utils
  907. wordShift :: Int
  908. wordShift = widthInLog wordWidth
  909. commafy :: [SDoc] -> SDoc
  910. commafy xs = hsep $ punctuate comma xs
  911. -- Print in C hex format: 0x13fa
  912. pprHexVal :: Integer -> Width -> SDoc
  913. pprHexVal 0 _ = ptext (sLit "0x0")
  914. pprHexVal w rep
  915. | w < 0 = parens (char '-' <> ptext (sLit "0x") <> go (-w) <> repsuffix rep)
  916. | otherwise = ptext (sLit "0x") <> go w <> repsuffix rep
  917. where
  918. -- type suffix for literals:
  919. -- Integer literals are unsigned in Cmm/C. We explicitly cast to
  920. -- signed values for doing signed operations, but at all other
  921. -- times values are unsigned. This also helps eliminate occasional
  922. -- warnings about integer overflow from gcc.
  923. -- on 32-bit platforms, add "ULL" to 64-bit literals
  924. repsuffix W64 | wORD_SIZE == 4 = ptext (sLit "ULL")
  925. -- on 64-bit platforms with 32-bit int, add "L" to 64-bit literals
  926. repsuffix W64 | cINT_SIZE == 4 = ptext (sLit "UL")
  927. repsuffix _ = char 'U'
  928. go 0 = empty
  929. go w' = go q <> dig
  930. where
  931. (q,r) = w' `quotRem` 16
  932. dig | r < 10 = char (chr (fromInteger r + ord '0'))
  933. | otherwise = char (chr (fromInteger r - 10 + ord 'a'))