1 {-# LANGUAGE ScopedTypeVariables #-}
3 module CLasH.Utils.GhcTools where
7 import qualified System.IO.Unsafe
10 import qualified Annotations
11 import qualified CoreSyn
12 import qualified CoreUtils
13 import qualified DynFlags
14 import qualified HscTypes
17 import qualified Serialized
19 import qualified Outputable
22 import CLasH.Utils.Pretty
23 import CLasH.Translator.TranslatorTypes
24 import CLasH.Translator.Annotations
27 listBindings :: FilePath -> [FilePath] -> IO [()]
28 listBindings libdir filenames = do
29 (cores,_,_) <- loadModules libdir filenames Nothing
30 let binds = concat $ map (CoreSyn.flattenBinds . HscTypes.cm_binds) cores
31 mapM (listBinding) binds
33 listBinding :: (CoreSyn.CoreBndr, CoreSyn.CoreExpr) -> IO ()
34 listBinding (b, e) = do
37 putStr "\nType of Binder: \n"
38 putStr $ Outputable.showSDoc $ Outputable.ppr $ Var.varType b
39 putStr "\n\nExpression: \n"
42 putStr $ Outputable.showSDoc $ Outputable.ppr e
43 putStr "\n\nType of Expression: \n"
44 putStr $ Outputable.showSDoc $ Outputable.ppr $ CoreUtils.exprType e
47 -- | Show the core structure of the given binds in the given file.
48 listBind :: FilePath -> [FilePath] -> String -> IO ()
49 listBind libdir filenames name = do
50 (cores,_,_) <- loadModules libdir filenames Nothing
51 bindings <- concatM $ mapM (findBinder (hasVarName name)) cores
52 mapM listBinding bindings
55 -- Change a DynFlag from within the Ghc monad. Strangely enough there seems to
56 -- be no standard function to do exactly this.
57 setDynFlag :: DynFlags.DynFlag -> GHC.Ghc ()
59 dflags <- GHC.getSessionDynFlags
60 let dflags' = DynFlags.dopt_set dflags dflag
61 GHC.setSessionDynFlags dflags'
64 -- We don't want the IO monad sprinkled around everywhere, so we hide it.
65 -- This should be safe as long as we only do simple things in the GhcMonad
66 -- such as interface lookups and evaluating simple expressions that
67 -- don't have side effects themselves (Or rather, that don't use
68 -- unsafePerformIO themselves, since normal side effectful function would
69 -- just return an IO monad when they are evaluated).
70 unsafeRunGhc :: FilePath -> GHC.Ghc a -> a
71 unsafeRunGhc libDir m =
72 System.IO.Unsafe.unsafePerformIO $ do
73 GHC.runGhc (Just libDir) $ do
74 dflags <- GHC.getSessionDynFlags
75 GHC.setSessionDynFlags dflags
78 -- | Loads the given files and turns it into a core module
80 FilePath -- ^ The GHC Library directory
81 -> [String] -- ^ The files that need to be loaded
82 -> Maybe Finder -- ^ What entities to build?
83 -> IO ( [HscTypes.CoreModule]
86 ) -- ^ ( The loaded modules, the resulting ghc environment, the entities to build)
87 loadModules libdir filenames finder =
88 GHC.defaultErrorHandler DynFlags.defaultDynFlags $ do
89 GHC.runGhc (Just libdir) $ do
90 dflags <- GHC.getSessionDynFlags
91 GHC.setSessionDynFlags dflags
92 cores <- mapM GHC.compileToCoreModule filenames
94 specs <- case finder of
96 Just f -> concatM $ mapM f cores
97 return (cores, env, specs)
102 -> HscTypes.CoreModule
103 -> m (Maybe CoreSyn.CoreBndr)
104 findBind criteria core = do
105 binders <- findBinder criteria core
108 bndrs -> return $ Just $ fst $ head bndrs
113 -> HscTypes.CoreModule
114 -> m (Maybe CoreSyn.CoreExpr)
115 findExpr criteria core = do
116 binders <- findBinder criteria core
119 bndrs -> return $ Just $ snd $ head bndrs
121 -- | Find a binder in module according to a certain criteria
124 (Var.Var -> m Bool) -- ^ The criteria to filter the binders on
125 -> HscTypes.CoreModule -- ^ The module to be inspected
126 -> m [(CoreSyn.CoreBndr, CoreSyn.CoreExpr)] -- ^ The binders to meet the criteria
127 findBinder criteria core = do
128 let binds = CoreSyn.flattenBinds $ HscTypes.cm_binds core
129 critbinds <- Monad.filterM (criteria . fst) binds
132 -- | Determine if a binder has an Annotation meeting a certain criteria
133 hasCLasHAnnotation ::
135 (CLasHAnn -> Bool) -- ^ The criteria the Annotation has to meet
136 -> Var.Var -- ^ The Binder
137 -> m Bool -- ^ Indicates if binder has the Annotation
138 hasCLasHAnnotation clashAnn var = do
139 let deserializer = Serialized.deserializeWithData
140 let target = Annotations.NamedTarget (Var.varName var)
141 (anns :: [CLasHAnn]) <- GHC.findGlobalAnns deserializer target
142 let annEnts = filter clashAnn anns
147 -- | Determine if a binder has a certain name
150 String -- ^ The name the binder has to have
151 -> Var.Var -- ^ The Binder
152 -> m Bool -- ^ Indicate if the binder has the name
153 hasVarName lookfor bind = return $ lookfor == (Name.occNameString $ Name.nameOccName $ Name.getName bind)
155 -- | Make a complete spec out of a three conditions
157 (Var.Var -> GHC.Ghc Bool) -> (Var.Var -> GHC.Ghc Bool) -> (Var.Var -> GHC.Ghc Bool)
160 findSpec topc statec testc mod = do
161 top <- findBind topc mod
162 state <- findExpr statec mod
163 test <- findExpr testc mod
164 return [(top, state, test)]
166 -- Just t -> return [(t, state, test)]
167 -- Nothing -> return error $ "Could not find top entity requested"