-vectBndrsIn :: [Var] -> VM a -> VM ([Var], [Var], a)
-vectBndrsIn vs p
- = localV
- $ do
- (vvs, lvs) <- mapAndUnzipM vectBndr vs
- x <- p
- return (vvs, lvs, x)
-
--- ----------------------------------------------------------------------------
--- Expressions
-
-replicateP :: CoreExpr -> CoreExpr -> VM CoreExpr
-replicateP expr len
- = do
- dict <- paDictOfType ty
- rep <- builtin replicatePAVar
- return $ mkApps (Var rep) [Type ty, dict, expr, len]
- where
- ty = exprType expr
-
-capply :: (CoreExpr, CoreExpr) -> (CoreExpr, CoreExpr) -> VM (CoreExpr, CoreExpr)
-capply (vfn, lfn) (varg, larg)
- = do
- apply <- builtin applyClosureVar
- applyP <- builtin applyClosurePVar
- return (mkApps (Var apply) [Type arg_ty, Type res_ty, vfn, varg],
- mkApps (Var applyP) [Type arg_ty, Type res_ty, lfn, larg])
- where
- fn_ty = exprType vfn
- (arg_ty, res_ty) = splitClosureTy fn_ty
-
-vectVar :: CoreExpr -> Var -> VM (CoreExpr, CoreExpr)
-vectVar lc v
- = do
- r <- lookupVar v
- case r of
- Local es -> return es
- Global vexpr -> do
- lexpr <- replicateP vexpr lc
- return (vexpr, lexpr)
-
-vectPolyVar :: CoreExpr -> Var -> [Type] -> VM (CoreExpr, CoreExpr)
-vectPolyVar lc v tys
- = do
- r <- lookupVar v
- case r of
- Local (vexpr, lexpr) -> liftM2 (,) (mk_app vexpr) (mk_app lexpr)
- Global poly -> do
- vexpr <- mk_app poly
- lexpr <- replicateP vexpr lc
- return (vexpr, lexpr)
- where
- mk_app e = applyToTypes e =<< mapM vectType tys
-
-abstractOverTyVars :: [TyVar] -> ((CoreExpr -> CoreExpr) -> VM a) -> VM a
-abstractOverTyVars tvs p
- = do
- mdicts <- mapM mk_dict_var tvs
- zipWithM_ (\tv -> maybe (deleteTyVarPA tv) (extendTyVarPA tv . Var)) tvs mdicts
- p (mk_lams mdicts)
- where
- mk_dict_var tv = do
- r <- paDictArgType tv
- case r of
- Just ty -> liftM Just (newLocalVar FSLIT("dPA") ty)
- Nothing -> return Nothing
-
- mk_lams mdicts = mkLams [arg | (tv, mdict) <- zip tvs mdicts
- , arg <- tv : maybeToList mdict]
-
-applyToTypes :: CoreExpr -> [Type] -> VM CoreExpr
-applyToTypes expr tys
- = do
- dicts <- mapM paDictOfType tys
- return $ mkApps expr [arg | (ty, dict) <- zip tys dicts
- , arg <- [Type ty, dict]]
-
-
-vectPolyExpr :: CoreExpr -> CoreExprWithFVs -> VM (CoreExpr, CoreExpr)
-vectPolyExpr lc expr
- = localV
- . abstractOverTyVars tvs $ \mk_lams ->
- -- FIXME: shadowing (tvs in lc)
- do
- (vmono, lmono) <- vectExpr lc mono
- return $ (mk_lams vmono, mk_lams lmono)
- where
- (tvs, mono) = collectAnnTypeBinders expr
-
-vectExpr :: CoreExpr -> CoreExprWithFVs -> VM (CoreExpr, CoreExpr)
-vectExpr lc (_, AnnType ty)
- = do
- vty <- vectType ty
- return (Type vty, Type vty)
-
-vectExpr lc (_, AnnVar v) = vectVar lc v
-
-vectExpr lc (_, AnnLit lit)
- = do
- let vexpr = Lit lit
- lexpr <- replicateP vexpr lc
- return (vexpr, lexpr)
-
-vectExpr lc (_, AnnNote note expr)
- = do
- (vexpr, lexpr) <- vectExpr lc expr
- return (Note note vexpr, Note note lexpr)
-
-vectExpr lc e@(_, AnnApp _ arg)
- | isAnnTypeArg arg
- = vectTyAppExpr lc fn tys
+-- | Vectorise a single module, in the VM monad.
+--
+vectModule :: ModGuts -> VM ModGuts
+vectModule guts@(ModGuts { mg_types = types
+ , mg_binds = binds
+ , mg_fam_insts = fam_insts
+ })
+ = do { dumpOptVt Opt_D_dump_vt_trace "Before vectorisation" $
+ pprCoreBindings binds
+
+ -- Vectorise the type environment.
+ -- This may add new TyCons and DataCons.
+ ; (types', new_fam_insts, tc_binds) <- vectTypeEnv types
+
+ ; (_, fam_inst_env) <- readGEnv global_fam_inst_env
+
+ -- dicts <- mapM buildPADict pa_insts
+ -- workers <- mapM vectDataConWorkers pa_insts
+
+ -- Vectorise all the top level bindings.
+ ; binds' <- mapM vectTopBind binds
+
+ ; return $ guts { mg_types = types'
+ , mg_binds = Rec tc_binds : binds'
+ , mg_fam_inst_env = fam_inst_env
+ , mg_fam_insts = fam_insts ++ new_fam_insts
+ }
+ }
+
+-- |Try to vectorise a top-level binding. If it doesn't vectorise then return it unharmed.
+--
+-- For example, for the binding
+--
+-- @
+-- foo :: Int -> Int
+-- foo = \x -> x + x
+-- @
+--
+-- we get
+-- @
+-- foo :: Int -> Int
+-- foo = \x -> vfoo $: x
+--
+-- v_foo :: Closure void vfoo lfoo
+-- v_foo = closure vfoo lfoo void
+--
+-- vfoo :: Void -> Int -> Int
+-- vfoo = ...
+--
+-- lfoo :: PData Void -> PData Int -> PData Int
+-- lfoo = ...
+-- @
+--
+-- @vfoo@ is the "vectorised", or scalar, version that does the same as the original
+-- function foo, but takes an explicit environment.
+--
+-- @lfoo@ is the "lifted" version that works on arrays.
+--
+-- @v_foo@ combines both of these into a `Closure` that also contains the
+-- environment.
+--
+-- The original binding @foo@ is rewritten to call the vectorised version
+-- present in the closure.
+--
+-- Vectorisation may be surpressed by annotating a binding with a 'NOVECTORISE' pragma. If this
+-- pragma is used in a group of mutually recursive bindings, either all or no binding must have
+-- the pragma. If only some bindings are annotated, a fatal error is being raised.
+-- FIXME: Once we support partial vectorisation, we may be able to vectorise parts of a group, or
+-- we may emit a warning and refrain from vectorising the entire group.
+--
+vectTopBind :: CoreBind -> VM CoreBind
+vectTopBind b@(NonRec var expr)
+ = unlessNoVectDecl $
+ do { -- Vectorise the right-hand side, create an appropriate top-level binding and add it
+ -- to the vectorisation map.
+ ; (inline, isScalar, expr') <- vectTopRhs [] var expr
+ ; var' <- vectTopBinder var inline expr'
+ ; when isScalar $
+ addGlobalScalar var
+
+ -- We replace the original top-level binding by a value projected from the vectorised
+ -- closure and add any newly created hoisted top-level bindings.
+ ; cexpr <- tryConvert var var' expr
+ ; hs <- takeHoisted
+ ; return . Rec $ (var, cexpr) : (var', expr') : hs
+ }
+ `orElseV`
+ return b