PageRenderTime 27ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/compiler/vectorise/Vectorise/Type/Env.hs

https://github.com/ezyang/ghc
Haskell | 457 lines | 225 code | 55 blank | 177 comment | 6 complexity | 57a76c2d94aff5eba6efa8bea4bec1e4 MD5 | raw file
  1. {-# LANGUAGE CPP #-}
  2. -- Vectorise a modules type and class declarations.
  3. --
  4. -- This produces new type constructors and family instances top be included in the module toplevel
  5. -- as well as bindings for worker functions, dfuns, and the like.
  6. module Vectorise.Type.Env (
  7. vectTypeEnv,
  8. ) where
  9. #include "HsVersions.h"
  10. import GhcPrelude
  11. import Vectorise.Env
  12. import Vectorise.Vect
  13. import Vectorise.Monad
  14. import Vectorise.Builtins
  15. import Vectorise.Type.TyConDecl
  16. import Vectorise.Type.Classify
  17. import Vectorise.Generic.PADict
  18. import Vectorise.Generic.PAMethods
  19. import Vectorise.Generic.PData
  20. import Vectorise.Generic.Description
  21. import Vectorise.Utils
  22. import CoreSyn
  23. import CoreUtils
  24. import CoreUnfold
  25. import DataCon
  26. import TyCon
  27. import CoAxiom
  28. import Type
  29. import FamInstEnv
  30. import Id
  31. import MkId
  32. import NameEnv
  33. import NameSet
  34. import UniqFM
  35. import OccName
  36. import Unique
  37. import Util
  38. import Outputable
  39. import DynFlags
  40. import FastString
  41. import MonadUtils
  42. import Control.Monad
  43. import Data.Maybe
  44. import Data.List
  45. -- Note [Pragmas to vectorise tycons]
  46. -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  47. --
  48. -- All imported type constructors that are not mapped to a vectorised type in the vectorisation map
  49. -- (possibly because the defining module was not compiled with vectorisation) may be used in scalar
  50. -- code encapsulated in vectorised code. If a such a type constructor 'T' is a member of the
  51. -- 'Scalar' class (and hence also of 'PData' and 'PRepr'), it may also be used in vectorised code,
  52. -- where 'T' represents itself, but the representation of 'T' still remains opaque in vectorised
  53. -- code (i.e., it can only be used in scalar code).
  54. --
  55. -- An example is the treatment of 'Int'. 'Int's can be used in vectorised code and remain unchanged
  56. -- by vectorisation. However, the representation of 'Int' by the 'I#' data constructor wrapping an
  57. -- 'Int#' is not exposed in vectorised code. Instead, computations involving the representation need
  58. -- to be confined to scalar code.
  59. --
  60. -- VECTORISE pragmas for type constructors cover four different flavours of vectorising data type
  61. -- constructors:
  62. --
  63. -- (1) Data type constructor 'T' that together with its constructors 'Cn' may be used in vectorised
  64. -- code, where 'T' and the 'Cn' are automatically vectorised in the same manner as data types
  65. -- declared in a vectorised module. This includes the case where the vectoriser determines that
  66. -- the original representation of 'T' may be used in vectorised code (as it does not embed any
  67. -- parallel arrays.) This case is for type constructors that are *imported* from a non-
  68. -- vectorised module, but that we want to use with full vectorisation support.
  69. --
  70. -- An example is the treatment of 'Ordering' and '[]'. The former remains unchanged by
  71. -- vectorisation, whereas the latter is fully vectorised.
  72. --
  73. -- 'PData' and 'PRepr' instances are automatically generated by the vectoriser.
  74. --
  75. -- Type constructors declared with {-# VECTORISE type T #-} are treated in this manner.
  76. --
  77. -- (2) Data type constructor 'T' that may be used in vectorised code, where 'T' is represented by an
  78. -- explicitly given 'Tv', but the representation of 'T' is opaque in vectorised code (i.e., the
  79. -- constructors of 'T' may not occur in vectorised code).
  80. --
  81. -- An example is the treatment of '[::]'. The type '[::]' can be used in vectorised code and is
  82. -- vectorised to 'PArray'. However, the representation of '[::]' is not exposed in vectorised
  83. -- code. Instead, computations involving the representation need to be confined to scalar code.
  84. --
  85. -- 'PData' and 'PRepr' instances need to be explicitly supplied for 'T' (they are not generated
  86. -- by the vectoriser).
  87. --
  88. -- Type constructors declared with {-# VECTORISE type T = Tv #-} are treated in this manner
  89. -- manner. (The vectoriser never treats a type constructor automatically in this manner.)
  90. --
  91. -- (3) Data type constructor 'T' that does not contain any parallel arrays and has explicitly
  92. -- provided 'PData' and 'PRepr' instances (and maybe also a 'Scalar' instance), which together
  93. -- with the type's constructors 'Cn' may be used in vectorised code. The type 'T' and its
  94. -- constructors 'Cn' are represented by themselves in vectorised code.
  95. --
  96. -- An example is 'Bool', which is represented by itself in vectorised code (as it cannot embed
  97. -- any parallel arrays). However, we do not want any automatic generation of class and family
  98. -- instances, which is why Case (1) does not apply.
  99. --
  100. -- 'PData' and 'PRepr' instances need to be explicitly supplied for 'T' (they are not generated
  101. -- by the vectoriser).
  102. --
  103. -- Type constructors declared with {-# VECTORISE SCALAR type T #-} are treated in this manner.
  104. --
  105. -- (4) Data type constructor 'T' that does not contain any parallel arrays and that, in vectorised
  106. -- code, is represented by an explicitly given 'Tv', but the representation of 'T' is opaque in
  107. -- vectorised code and 'T' is regarded to be scalar i.e., it may be used in encapsulated
  108. -- scalar subcomputations.
  109. --
  110. -- An example is the treatment of '(->)'. Types '(->)' can be used in vectorised code and are
  111. -- vectorised to '(:->)'. However, the representation of '(->)' is not exposed in vectorised
  112. -- code. Instead, computations involving the representation need to be confined to scalar code
  113. -- and may be part of encapsulated scalar computations.
  114. --
  115. -- 'PData' and 'PRepr' instances need to be explicitly supplied for 'T' (they are not generated
  116. -- by the vectoriser).
  117. --
  118. -- Type constructors declared with {-# VECTORISE SCALAR type T = Tv #-} are treated in this
  119. -- manner. (The vectoriser never treats a type constructor automatically in this manner.)
  120. --
  121. -- In addition, we have also got a single pragma form for type classes: {-# VECTORISE class C #-}.
  122. -- It implies that the class type constructor may be used in vectorised code together with its data
  123. -- constructor. We generally produce a vectorised version of the data type and data constructor.
  124. -- We do not generate 'PData' and 'PRepr' instances for class type constructors. This pragma is the
  125. -- default for all type classes declared in a vectorised module, but the pragma can also be used
  126. -- explitly on imported classes.
  127. -- Note [Vectorising classes]
  128. -- ~~~~~~~~~~~~~~~~~~~~~~~~~~
  129. --
  130. -- We vectorise classes essentially by just vectorising their desugared Core representation, but we
  131. -- do generate a 'Class' structure along the way (see 'Vectorise.Type.TyConDecl.vectTyConDecl').
  132. --
  133. -- Here is an example illustrating the mapping assume
  134. --
  135. -- class Num a where
  136. -- (+) :: a -> a -> a
  137. --
  138. -- It desugars to
  139. --
  140. -- data Num a = D:Num { (+) :: a -> a -> a }
  141. --
  142. -- which we vectorise to
  143. --
  144. -- data V:Num a = D:V:Num { ($v+) :: PArray a :-> PArray a :-> PArray a }
  145. --
  146. -- while adding the following entries to the vectorisation map:
  147. --
  148. -- tycon : Num --> V:Num
  149. -- datacon: D:Num --> D:V:Num
  150. -- var : (+) --> ($v+)
  151. -- |Vectorise type constructor including class type constructors.
  152. --
  153. vectTypeEnv :: [TyCon] -- Type constructors defined in this module
  154. -> [CoreVect] -- All 'VECTORISE [SCALAR] type' declarations in this module
  155. -> [CoreVect] -- All 'VECTORISE class' declarations in this module
  156. -> VM ( [TyCon] -- old TyCons ++ new TyCons
  157. , [FamInst] -- New type family instances.
  158. , [(Var, CoreExpr)]) -- New top level bindings.
  159. vectTypeEnv tycons vectTypeDecls vectClassDecls
  160. = do { traceVt "** vectTypeEnv" $ ppr tycons
  161. ; let -- {-# VECTORISE type T -#} (ONLY the imported tycons)
  162. impVectTyCons = ( [tycon | VectType False tycon Nothing <- vectTypeDecls]
  163. ++ [tycon | VectClass tycon <- vectClassDecls])
  164. \\ tycons
  165. -- {-# VECTORISE type T = Tv -#} (imported & local tycons with an /RHS/)
  166. vectTyConsWithRHS = [ (tycon, rhs)
  167. | VectType False tycon (Just rhs) <- vectTypeDecls]
  168. -- {-# VECTORISE SCALAR type T = Tv -#} (imported & local tycons with an /RHS/)
  169. scalarTyConsWithRHS = [ (tycon, rhs)
  170. | VectType True tycon (Just rhs) <- vectTypeDecls]
  171. -- {-# VECTORISE SCALAR type T -#} (imported & local /scalar/ tycons without an RHS)
  172. scalarTyConsNoRHS = [tycon | VectType True tycon Nothing <- vectTypeDecls]
  173. -- Check that is not a VECTORISE SCALAR tycon nor VECTORISE tycons with explicit rhs?
  174. vectSpecialTyConNames = mkNameSet . map tyConName $
  175. scalarTyConsNoRHS ++
  176. map fst (vectTyConsWithRHS ++ scalarTyConsWithRHS)
  177. notVectSpecialTyCon tc = not $ (tyConName tc) `elemNameSet` vectSpecialTyConNames
  178. -- Build a map containing all vectorised type constructor. If the vectorised type
  179. -- constructor differs from the original one, then it is mapped to 'True'; if they are
  180. -- both the same, then it maps to 'False'.
  181. ; vectTyCons <- globalVectTyCons
  182. ; let vectTyConBase = mapUFM_Directly isDistinct vectTyCons -- 'True' iff tc /= V[[tc]]
  183. isDistinct u tc = u /= getUnique tc
  184. vectTyConFlavour = vectTyConBase
  185. `plusNameEnv`
  186. mkNameEnv [ (tyConName tycon, True)
  187. | (tycon, _) <- vectTyConsWithRHS ++ scalarTyConsWithRHS]
  188. `plusNameEnv`
  189. mkNameEnv [ (tyConName tycon, False) -- original representation
  190. | tycon <- scalarTyConsNoRHS]
  191. -- Split the list of 'TyCons' into the ones (1) that we must vectorise and those (2)
  192. -- that we could, but don't need to vectorise. Type constructors that are not data
  193. -- type constructors or use non-Haskell98 features are being dropped. They may not
  194. -- appear in vectorised code. (We also drop the local type constructors appearing in a
  195. -- VECTORISE SCALAR pragma or a VECTORISE pragma with an explicit right-hand side, as
  196. -- these are being handled separately. NB: Some type constructors may be marked SCALAR
  197. -- /and/ have an explicit right-hand side.)
  198. --
  199. -- Furthermore, 'par_tcs' are those type constructors (converted or not) whose
  200. -- definition, directly or indirectly, depends on parallel arrays. Finally, 'drop_tcs'
  201. -- are all type constructors that cannot be vectorised.
  202. ; parallelTyCons <- (`extendNameSetList` map (tyConName . fst) vectTyConsWithRHS) <$>
  203. globalParallelTyCons
  204. ; let maybeVectoriseTyCons = filter notVectSpecialTyCon tycons ++ impVectTyCons
  205. (conv_tcs, keep_tcs, par_tcs, drop_tcs)
  206. = classifyTyCons vectTyConFlavour parallelTyCons maybeVectoriseTyCons
  207. ; traceVt " known parallel : " $ ppr parallelTyCons
  208. ; traceVt " VECT SCALAR : " $ ppr (scalarTyConsNoRHS ++ map fst scalarTyConsWithRHS)
  209. ; traceVt " VECT [class] : " $ ppr impVectTyCons
  210. ; traceVt " VECT with rhs : " $ ppr (map fst (vectTyConsWithRHS ++ scalarTyConsWithRHS))
  211. ; traceVt " -- after classification (local and VECT [class] tycons) --" Outputable.empty
  212. ; traceVt " reuse : " $ ppr keep_tcs
  213. ; traceVt " convert : " $ ppr conv_tcs
  214. -- warn the user about unvectorised type constructors
  215. ; let explanation = text "(They use unsupported language extensions"
  216. $$ text "or depend on type constructors that are" <+>
  217. text "not vectorised)"
  218. drop_tcs_nosyn = filter (not . isTypeFamilyTyCon) .
  219. filter (not . isTypeSynonymTyCon) $ drop_tcs
  220. ; unless (null drop_tcs_nosyn) $
  221. emitVt "Warning: cannot vectorise these type constructors:" $
  222. pprQuotedList drop_tcs_nosyn $$ explanation
  223. ; mapM_ addParallelTyConAndCons $ par_tcs ++ map fst vectTyConsWithRHS
  224. ; let mapping =
  225. -- Type constructors that we found we don't need to vectorise and those
  226. -- declared VECTORISE SCALAR /without/ an explicit right-hand side, use the same
  227. -- representation in both unvectorised and vectorised code; they are not
  228. -- abstract.
  229. [(tycon, tycon, False) | tycon <- keep_tcs ++ scalarTyConsNoRHS]
  230. -- We do the same for type constructors declared VECTORISE SCALAR /without/
  231. -- an explicit right-hand side
  232. ++ [(tycon, vTycon, True) | (tycon, vTycon) <- vectTyConsWithRHS ++ scalarTyConsWithRHS]
  233. ; syn_tcs <- catMaybes <$> mapM defTyConDataCons mapping
  234. -- Vectorise all the data type declarations that we can and must vectorise (enter the
  235. -- type and data constructors into the vectorisation map on-the-fly.)
  236. ; new_tcs <- vectTyConDecls conv_tcs
  237. ; let dumpTc tc vTc = traceVt "---" (ppr tc <+> text "::" <+> ppr (dataConSig tc) $$
  238. ppr vTc <+> text "::" <+> ppr (dataConSig vTc))
  239. dataConSig tc | Just dc <- tyConSingleDataCon_maybe tc = dataConRepType dc
  240. | otherwise = panic "dataConSig"
  241. ; zipWithM_ dumpTc (filter isClassTyCon conv_tcs) (filter isClassTyCon new_tcs)
  242. -- We don't need new representation types for dictionary constructors. The constructors
  243. -- are always fully applied, and we don't need to lift them to arrays as a dictionary
  244. -- of a particular type always has the same value.
  245. ; let orig_tcs = filter (not . isClassTyCon) $ keep_tcs ++ conv_tcs
  246. vect_tcs = filter (not . isClassTyCon) $ keep_tcs ++ new_tcs
  247. -- Build 'PRepr' and 'PData' instance type constructors and family instances for all
  248. -- type constructors with vectorised representations.
  249. ; reprs <- mapM tyConRepr vect_tcs
  250. ; repr_fis <- zipWith3M buildPReprTyCon orig_tcs vect_tcs reprs
  251. ; pdata_fis <- zipWith3M buildPDataTyCon orig_tcs vect_tcs reprs
  252. ; pdatas_fis <- zipWith3M buildPDatasTyCon orig_tcs vect_tcs reprs
  253. ; let fam_insts = repr_fis ++ pdata_fis ++ pdatas_fis
  254. repr_axs = map famInstAxiom repr_fis
  255. pdata_tcs = famInstsRepTyCons pdata_fis
  256. pdatas_tcs = famInstsRepTyCons pdatas_fis
  257. ; updGEnv $ extendFamEnv fam_insts
  258. -- Generate workers for the vectorised data constructors, dfuns for the 'PA' instances of
  259. -- the vectorised type constructors, and associate the type constructors with their dfuns
  260. -- in the global environment. We get back the dfun bindings (which we will subsequently
  261. -- inject into the modules toplevel).
  262. ; (_, binds) <- fixV $ \ ~(dfuns, _) ->
  263. do { defTyConPAs (zipLazy vect_tcs dfuns)
  264. -- Query the 'PData' instance type constructors for type constructors that have a
  265. -- VECTORISE SCALAR type pragma without an explicit right-hand side (this is Item
  266. -- (3) of "Note [Pragmas to vectorise tycons]" above).
  267. ; pdata_scalar_tcs <- mapM pdataReprTyConExact scalarTyConsNoRHS
  268. -- Build workers for all vectorised data constructors (except abstract ones)
  269. ; sequence_ $
  270. zipWith3 vectDataConWorkers (orig_tcs ++ scalarTyConsNoRHS)
  271. (vect_tcs ++ scalarTyConsNoRHS)
  272. (pdata_tcs ++ pdata_scalar_tcs)
  273. -- Build a 'PA' dictionary for all type constructors (except abstract ones & those
  274. -- defined with an explicit right-hand side where the dictionary is user-supplied)
  275. ; dfuns <- sequence $
  276. zipWith4 buildTyConPADict
  277. vect_tcs
  278. repr_axs
  279. pdata_tcs
  280. pdatas_tcs
  281. ; binds <- takeHoisted
  282. ; return (dfuns, binds)
  283. }
  284. -- Return the vectorised variants of type constructors as well as the generated instance
  285. -- type constructors, family instances, and dfun bindings.
  286. ; return ( new_tcs ++ pdata_tcs ++ pdatas_tcs ++ syn_tcs
  287. , fam_insts, binds)
  288. }
  289. where
  290. addParallelTyConAndCons tycon
  291. = do
  292. { addGlobalParallelTyCon tycon
  293. ; mapM_ addGlobalParallelVar [ id | dc <- tyConDataCons tycon
  294. , AnId id <- dataConImplicitTyThings dc ]
  295. -- Ignoring the promoted tycon; hope that's ok
  296. }
  297. -- Add a mapping from the original to vectorised type constructor to the vectorisation map.
  298. -- Unless the type constructor is abstract, also mappings from the original's data constructors
  299. -- to the vectorised type's data constructors.
  300. --
  301. -- We have three cases: (1) original and vectorised type constructor are the same, (2) the
  302. -- name of the vectorised type constructor is canonical (as prescribed by 'mkVectTyConOcc'), or
  303. -- (3) the name is not canonical. In the third case, we additionally introduce a type synonym
  304. -- with the canonical name that is set equal to the non-canonical name (so that we find the
  305. -- right type constructor when reading vectorisation information from interface files).
  306. --
  307. defTyConDataCons (origTyCon, vectTyCon, isAbstract)
  308. = do
  309. { canonName <- mkLocalisedName mkVectTyConOcc origName
  310. ; if origName == vectName -- Case (1)
  311. || vectName == canonName -- Case (2)
  312. then do
  313. { defTyCon origTyCon vectTyCon -- T --> vT
  314. ; defDataCons -- Ci --> vCi
  315. ; return Nothing
  316. }
  317. else do -- Case (3)
  318. { let synTyCon = mkSyn canonName (mkTyConTy vectTyCon) -- type S = vT
  319. ; defTyCon origTyCon synTyCon -- T --> S
  320. ; defDataCons -- Ci --> vCi
  321. ; return $ Just synTyCon
  322. }
  323. }
  324. where
  325. origName = tyConName origTyCon
  326. vectName = tyConName vectTyCon
  327. mkSyn canonName ty = buildSynTyCon canonName [] (typeKind ty) [] ty
  328. defDataCons
  329. | isAbstract = return ()
  330. | otherwise
  331. = do { MASSERT(tyConDataCons origTyCon `equalLength` tyConDataCons vectTyCon)
  332. ; zipWithM_ defDataCon (tyConDataCons origTyCon) (tyConDataCons vectTyCon)
  333. }
  334. -- Helpers --------------------------------------------------------------------
  335. buildTyConPADict :: TyCon -> CoAxiom Unbranched -> TyCon -> TyCon -> VM Var
  336. buildTyConPADict vect_tc prepr_ax pdata_tc pdatas_tc
  337. = tyConRepr vect_tc >>= buildPADict vect_tc prepr_ax pdata_tc pdatas_tc
  338. -- Produce a custom-made worker for the data constructors of a vectorised data type. This includes
  339. -- all data constructors that may be used in vectorised code i.e., all data constructors of data
  340. -- types with 'VECTORISE [SCALAR] type' pragmas with an explicit right-hand side. Also adds a mapping
  341. -- from the original to vectorised worker into the vectorisation map.
  342. --
  343. -- FIXME: It's not nice that we need create a special worker after the data constructors has
  344. -- already been constructed. Also, I don't think the worker is properly added to the data
  345. -- constructor. Seems messy.
  346. vectDataConWorkers :: TyCon -> TyCon -> TyCon -> VM ()
  347. vectDataConWorkers orig_tc vect_tc arr_tc
  348. = do { traceVt "Building vectorised worker for datatype" (ppr orig_tc)
  349. ; bs <- sequence
  350. . zipWith3 def_worker (tyConDataCons orig_tc) rep_tys
  351. $ zipWith4 mk_data_con (tyConDataCons vect_tc)
  352. rep_tys
  353. (inits rep_tys)
  354. (tail $ tails rep_tys)
  355. ; mapM_ (uncurry hoistBinding) bs
  356. }
  357. where
  358. tyvars = tyConTyVars vect_tc
  359. var_tys = mkTyVarTys tyvars
  360. ty_args = map Type var_tys
  361. res_ty = mkTyConApp vect_tc var_tys
  362. cons = tyConDataCons vect_tc
  363. arity = length cons
  364. [arr_dc] = tyConDataCons arr_tc
  365. rep_tys = map dataConRepArgTys $ tyConDataCons vect_tc
  366. mk_data_con con tys pre post
  367. = do dflags <- getDynFlags
  368. liftM2 (,) (vect_data_con con)
  369. (lift_data_con tys pre post (mkDataConTag dflags con))
  370. sel_replicate len tag
  371. | arity > 1 = do
  372. rep <- builtin (selReplicate arity)
  373. return [rep `mkApps` [len, tag]]
  374. | otherwise = return []
  375. vect_data_con con = return $ mkConApp con ty_args
  376. lift_data_con tys pre_tys post_tys tag
  377. = do
  378. len <- builtin liftingContext
  379. args <- mapM (newLocalVar (fsLit "xs"))
  380. =<< mapM mkPDataType tys
  381. sel <- sel_replicate (Var len) tag
  382. pre <- mapM emptyPD (concat pre_tys)
  383. post <- mapM emptyPD (concat post_tys)
  384. return . mkLams (len : args)
  385. . wrapFamInstBody arr_tc var_tys
  386. . mkConApp arr_dc
  387. $ ty_args ++ sel ++ pre ++ map Var args ++ post
  388. def_worker data_con arg_tys mk_body
  389. = do
  390. arity <- polyArity tyvars
  391. body <- closedV
  392. . inBind orig_worker
  393. . polyAbstract tyvars $ \args ->
  394. liftM (mkLams (tyvars ++ args) . vectorised)
  395. $ buildClosures tyvars [] [] arg_tys res_ty mk_body
  396. raw_worker <- mkVectId orig_worker (exprType body)
  397. let vect_worker = raw_worker `setIdUnfolding`
  398. mkInlineUnfoldingWithArity arity body
  399. defGlobalVar orig_worker vect_worker
  400. return (vect_worker, body)
  401. where
  402. orig_worker = dataConWorkId data_con