PageRenderTime 42ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Gen2/Sinker.hs

http://github.com/ghcjs/ghcjs
Haskell | 168 lines | 121 code | 20 blank | 27 comment | 5 complexity | f35f85915d7e41b7acad4a33def10444 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0
  1. {-# LANGUAGE TupleSections, CPP #-}
  2. module Gen2.Sinker (sinkPgm) where
  3. import UniqSet
  4. import VarSet
  5. import UniqFM
  6. import StgSyn
  7. import Id
  8. import Name
  9. import Module
  10. import Literal
  11. import Gen2.GHC.Digraph
  12. import Control.Lens
  13. import Data.Char
  14. import Data.Either
  15. import Data.List (partition)
  16. import Data.Maybe
  17. import Gen2.ClosureInfo
  18. {- |
  19. GHC floats constants to the top level. This is fine in native code, but with JS
  20. they occupy some global variable name. We can unfloat some unexported things:
  21. - global constructors, as long as they're referenced only once by another global
  22. constructor and are not in a recursive binding group
  23. - literals (small literals may also be sunk if they are used more than once)
  24. -}
  25. sinkPgm :: Module
  26. -> [StgTopBinding]
  27. -> (UniqFM StgExpr, [StgTopBinding])
  28. sinkPgm m pgm = (sunk, map StgTopLifted pgm'' ++ stringLits)
  29. where
  30. selectLifted (StgTopLifted b) = Left b
  31. selectLifted x = Right x
  32. (pgm', stringLits) = partitionEithers (map selectLifted pgm)
  33. (sunk, pgm'') = sinkPgm' m pgm'
  34. sinkPgm' :: Module -- ^ the module, since we treat definitions from the
  35. -- current module differently
  36. -> [StgBinding] -- ^ the bindings
  37. -> (UniqFM StgExpr, [StgBinding]) -- ^ a map with sunken replacements for nodes, for where
  38. -- the replacement does not fit in the 'StgBinding' AST
  39. -- and the new bindings
  40. sinkPgm' m pgm =
  41. let usedOnce = collectUsedOnce pgm
  42. sinkables = listToUFM $
  43. concatMap alwaysSinkable pgm ++
  44. filter ((`elementOfUniqSet` usedOnce) . fst) (concatMap (onceSinkable m) pgm)
  45. isSunkBind (StgNonRec b _e) | elemUFM b sinkables = True
  46. isSunkBind _ = False
  47. in (sinkables, filter (not . isSunkBind) $ topSortDecls m pgm)
  48. {- |
  49. always sinkable, values that may be duplicated in the generated code:
  50. * small literals
  51. -}
  52. alwaysSinkable :: StgBinding -> [(Id, StgExpr)]
  53. alwaysSinkable (StgNonRec b rhs)
  54. | (StgRhsClosure _ccs _bi _ _upd _srt e@(StgLit l)) <- rhs,
  55. isSmallSinkableLit l && isLocal b = [(b,e)]
  56. | (StgRhsCon _ccs dc as@[StgLitArg l]) <- rhs,
  57. isSmallSinkableLit l && isLocal b && isUnboxableCon dc = [(b,StgConApp dc as [])]
  58. alwaysSinkable _ = []
  59. isSmallSinkableLit :: Literal -> Bool
  60. isSmallSinkableLit (MachChar c) = ord c < 100000
  61. isSmallSinkableLit (LitNumber _ i _) = i > -100000 && i < 100000
  62. isSmallSinkableLit _ = False
  63. {- |
  64. once sinkable: may be sunk, but duplication is not ok
  65. -}
  66. onceSinkable :: Module -> StgBinding -> [(Id, StgExpr)]
  67. onceSinkable _m (StgNonRec b rhs)
  68. | Just e <- getSinkable rhs, isLocal b = [(b,e)]
  69. where
  70. getSinkable (StgRhsCon _ccs dc args)
  71. = Just (StgConApp dc args [])
  72. getSinkable (StgRhsClosure _ccs _bi _ _upd _ e@(StgLit{}))
  73. = Just e
  74. getSinkable _ = Nothing
  75. onceSinkable _ _ = []
  76. -- | collect all idents used only once in an argument at the top level
  77. -- and never anywhere else
  78. collectUsedOnce :: [StgBinding] -> IdSet
  79. collectUsedOnce binds = intersectUniqSets (usedOnce foldArgs) (usedOnce foldArgsTop)
  80. where
  81. usedOnce f = fst . foldrOf (traverse . f) g (emptyUniqSet, emptyUniqSet) $ binds
  82. g i t@(once, mult)
  83. | i `elementOfUniqSet` mult = t
  84. | i `elementOfUniqSet` once
  85. = (delOneFromUniqSet once i, addOneToUniqSet mult i)
  86. | otherwise = (addOneToUniqSet once i, mult)
  87. -- | fold over all id in StgArg used at the top level in an StgRhsCon
  88. foldArgsTop :: Fold StgBinding Id
  89. foldArgsTop f e@(StgNonRec b r)
  90. | (StgRhsCon ccs dc args) <- r =
  91. StgNonRec b . StgRhsCon ccs dc <$> (traverse . foldArgsA) f args
  92. | otherwise = pure e
  93. foldArgsTop f (StgRec bs) =
  94. StgRec <$> sequenceA (map (\(b,r) -> (,) b <$> g r) bs)
  95. where
  96. g (StgRhsCon ccs dc args) =
  97. StgRhsCon ccs dc <$> (traverse . foldArgsA) f args
  98. g x = pure x
  99. -- | fold over all Id in StgArg in the AST
  100. foldArgs :: Fold StgBinding Id
  101. foldArgs f (StgNonRec b r) = StgNonRec b <$> foldArgsR f r
  102. foldArgs f (StgRec bs) =
  103. StgRec <$> sequenceA (map (\(b,r) -> (,) b <$> foldArgsR f r) bs)
  104. foldArgsR :: Fold StgRhs Id
  105. foldArgsR f (StgRhsClosure x0 x1 x2 x3 x4 e) =
  106. StgRhsClosure x0 x1 x2 x3 x4 <$> foldArgsE f e
  107. foldArgsR f (StgRhsCon x y args) =
  108. StgRhsCon x y <$> (traverse . foldArgsA) f args
  109. foldArgsE :: Fold StgExpr Id
  110. foldArgsE f (StgApp x args) = StgApp <$> f x <*> (traverse . foldArgsA) f args
  111. foldArgsE f (StgConApp c args ts) = StgConApp c <$> (traverse . foldArgsA) f args <*> pure ts
  112. foldArgsE f (StgOpApp x args t) = StgOpApp x <$> (traverse . foldArgsA) f args <*> pure t
  113. foldArgsE f (StgLam b e) = StgLam b <$> foldArgsE f e
  114. foldArgsE f (StgCase e b a alts) =
  115. StgCase <$> foldArgsE f e
  116. <*> pure b <*> pure a
  117. <*> sequenceA (map (\(ac,bs,e) -> (,,) ac bs <$> foldArgsE f e) alts)
  118. foldArgsE f (StgLet b e) = StgLet <$> foldArgs f b <*> foldArgsE f e
  119. foldArgsE f (StgLetNoEscape b e) = StgLetNoEscape <$> foldArgs f b <*> foldArgsE f e
  120. foldArgsE f (StgTick i e) = StgTick i <$> foldArgsE f e
  121. foldArgsE _ e = pure e
  122. foldArgsA :: Fold StgArg Id
  123. foldArgsA f (StgVarArg i) = StgVarArg <$> f i
  124. foldArgsA _ a = pure a
  125. isLocal :: Id -> Bool
  126. isLocal i = isNothing (nameModule_maybe . idName $ i) && not (isExportedId i)
  127. {- | since we have sequential initialization,
  128. topsort the non-recursive constructor bindings
  129. -}
  130. topSortDecls :: Module -> [StgBinding] -> [StgBinding]
  131. topSortDecls _m binds = rest ++ nr'
  132. where
  133. (nr, rest) = partition isNonRec binds
  134. isNonRec (StgNonRec {}) = True
  135. isNonRec _ = False
  136. vs = map getV nr
  137. keys = mkUniqSet (map snd vs)
  138. getV e@(StgNonRec b _) = (e, b)
  139. getV _ = error "topSortDecls: getV, unexpected binding"
  140. collectDeps (StgNonRec b (StgRhsCon _ _dc args)) =
  141. [ (i, b) | StgVarArg i <- args, i `elementOfUniqSet` keys ]
  142. collectDeps _ = []
  143. g = graphFromVerticesAndAdjacency vs (concatMap collectDeps nr)
  144. nr' | (not . null) [()| CyclicSCC _ <- stronglyConnCompG g]
  145. = error "topSortDecls: unexpected cycle"
  146. | otherwise = map fst (topologicalSortG g)