@@ -28,9 +28,9 @@ module Clash.Normalize.Transformations.Specialize
2828 ) where
2929
3030import Control.Arrow ((***) , (&&&) )
31- import Control.DeepSeq (deepseq )
31+ import qualified Control.Concurrent.MVar.Lifted as MVar
32+ import Control.DeepSeq (force )
3233import Control.Exception (throw )
33- import Control.Lens ((%=) )
3434import qualified Control.Lens as Lens
3535import qualified Control.Monad as Monad
3636import Control.Monad.Extra (orM )
@@ -387,74 +387,78 @@ specialize' (TransformContext is0 _) e (Var f, args, ticks) specArgIn = do
387387 specAbs :: Either Term Type
388388 specAbs = either (Left . stripAllTicks . (`mkAbstraction` specBndrs)) (Right . id ) specArg
389389 -- Determine if 'f' has already been specialized on (a type-normalized) 'specArg'
390- specM <- Map. lookup (f,argLen,specAbs) <$> Lens. use (extra. specialisationCache)
391- case specM of
392- -- Use previously specialized function
393- Just f' ->
394- traceIf (hasTransformationInfo AppliedTerm opts)
395- (" Using previous specialization of " ++ showPpr (varName f) ++ " on " ++
396- (either showPpr showPpr) specAbs ++ " : " ++ showPpr (varName f')) $
397- changed $ mkApps (mkTicks (Var f') ticks) (args ++ specVars)
398- -- Create new specialized function
399- Nothing -> do
400- -- Determine if we can specialize f
401- bodyMaybe <- fmap (lookupUniqMap (varName f)) $ Lens. use bindings
402- case bodyMaybe of
403- Just (Binding _ sp inl _ bodyTm _) -> do
404- -- Determine if we see a sequence of specializations on a growing argument
405- specHistM <- lookupUniqMap f <$> Lens. use (extra. specialisationHistory)
406- specLim <- Lens. view specializationLimit
407- if maybe False (> specLim) specHistM
408- then throw (ClashException
409- sp
410- (unlines [ " Hit specialization limit " ++ show specLim ++ " on function `" ++ showPpr (varName f) ++ " '.\n "
411- , " The function `" ++ showPpr f ++ " ' is most likely recursive, and looks like it is being indefinitely specialized on a growing argument.\n "
412- , " Body of `" ++ showPpr f ++ " ':\n " ++ showPpr bodyTm ++ " \n "
413- , " Argument (in position: " ++ show argLen ++ " ) that triggered termination:\n " ++ (either showPpr showPpr) specArg
414- , " Run with '-fclash-spec-limit=N' to increase the specialization limit to N."
415- ])
416- Nothing )
417- else do
418- let existingNames = collectBndrsMinusApps bodyTm
419- newNames = [ mkUnsafeInternalName (" pTS" `Text.append` Text. pack (show n)) n
420- | n <- [(0 :: Int ).. ]
421- ]
422- -- Make new binders for existing arguments
423- (boundArgs,argVars) <- fmap (unzip . map (either (Left &&& Left . Var ) (Right &&& Right . VarTy ))) $
424- Monad. zipWithM
425- (mkBinderFor is0 tcm)
426- (existingNames ++ newNames)
427- args
428- -- Determine name the resulting specialized function, and the
429- -- form of the specialized-on argument
430- (fId,inl',specArg') <- case specArg of
431- Left a@ (collectArgsTicks -> (Var g,gArgs,_gTicks)) -> if isPolyFun tcm a
432- then do
433- -- In case we are specialising on an argument that is a
434- -- global function then we use that function's name as the
435- -- name of the specialized higher-order function.
436- -- Additionally, we will return the body of the global
437- -- function, instead of a variable reference to the
438- -- global function.
439- --
440- -- This will turn things like @mealy g k@ into a new
441- -- binding @g'@ where both the body of @mealy@ and @g@
442- -- are inlined, meaning the state-transition-function
443- -- and the memory element will be in a single function.
444- gTmM <- fmap (lookupUniqMap (varName g)) $ Lens. use bindings
445- return (g,maybe inl bindingSpec gTmM, maybe specArg (Left . (`mkApps` gArgs) . bindingTerm) gTmM)
446- else return (f,inl,specArg)
447- _ -> return (f,inl,specArg)
448- -- Create specialized functions
449- let newBody = mkAbstraction (mkApps bodyTm (argVars ++ [specArg'])) (boundArgs ++ specBndrs)
450- newf <- mkFunction (varName fId) sp inl' newBody
451- -- Remember specialization
452- (extra. specialisationHistory) %= extendUniqMapWith f 1 (+)
453- (extra. specialisationCache) %= Map. insert (f,argLen,specAbs) newf
454- -- use specialized function
455- let newExpr = mkApps (mkTicks (Var newf) ticks) (args ++ specVars)
456- newf `deepseq` changed newExpr
457- Nothing -> return e
390+ specCacheV <- Lens. use (extra. specialisationCache)
391+
392+ MVar. modifyMVar specCacheV $ \ specCache ->
393+ case Map. lookup (f, argLen, specAbs) specCache of
394+ -- Use previously specialized function
395+ Just f' ->
396+ traceIf (hasTransformationInfo AppliedTerm opts)
397+ (" Using previous specialization of " ++ showPpr (varName f) ++ " on " ++
398+ (either showPpr showPpr) specAbs ++ " : " ++ showPpr (varName f')) $
399+ changed (specCache, mkApps (mkTicks (Var f') ticks) (args ++ specVars))
400+ -- Create new specialized function
401+ Nothing -> do
402+ -- Determine if we can specialize f
403+ bodyMaybe <- fmap (lookupUniqMap (varName f)) $ Lens. use bindings
404+ case bodyMaybe of
405+ Just (Binding _ sp inl _ bodyTm _) -> do
406+ -- Determine if we see a sequence of specializations on a growing argument
407+ specHistMV <- Lens. use (extra. specialisationHistory)
408+ specHist <- MVar. takeMVar specHistMV
409+ let specHistM = lookupUniqMap f specHist
410+ specLim <- Lens. view specializationLimit
411+ if maybe False (> specLim) specHistM
412+ then throw (ClashException
413+ sp
414+ (unlines [ " Hit specialization limit " ++ show specLim ++ " on function `" ++ showPpr (varName f) ++ " '.\n "
415+ , " The function `" ++ showPpr f ++ " ' is most likely recursive, and looks like it is being indefinitely specialized on a growing argument.\n "
416+ , " Body of `" ++ showPpr f ++ " ':\n " ++ showPpr bodyTm ++ " \n "
417+ , " Argument (in position: " ++ show argLen ++ " ) that triggered termination:\n " ++ (either showPpr showPpr) specArg
418+ , " Run with '-fclash-spec-limit=N' to increase the specialization limit to N."
419+ ])
420+ Nothing )
421+ else do
422+ let existingNames = collectBndrsMinusApps bodyTm
423+ newNames = [ mkUnsafeInternalName (" pTS" `Text.append` Text. pack (show n)) n
424+ | n <- [(0 :: Int ).. ]
425+ ]
426+ -- Make new binders for existing arguments
427+ (boundArgs,argVars) <- fmap (unzip . map (either (Left &&& Left . Var ) (Right &&& Right . VarTy ))) $
428+ Monad. zipWithM
429+ (mkBinderFor is0 tcm)
430+ (existingNames ++ newNames)
431+ args
432+ -- Determine name the resulting specialized function, and the
433+ -- form of the specialized-on argument
434+ (fId,inl',specArg') <- case specArg of
435+ Left a@ (collectArgsTicks -> (Var g,gArgs,_gTicks)) -> if isPolyFun tcm a
436+ then do
437+ -- In case we are specialising on an argument that is a
438+ -- global function then we use that function's name as the
439+ -- name of the specialized higher-order function.
440+ -- Additionally, we will return the body of the global
441+ -- function, instead of a variable reference to the
442+ -- global function.
443+ --
444+ -- This will turn things like @mealy g k@ into a new
445+ -- binding @g'@ where both the body of @mealy@ and @g@
446+ -- are inlined, meaning the state-transition-function
447+ -- and the memory element will be in a single function.
448+ gTmM <- fmap (lookupUniqMap (varName g)) $ Lens. use bindings
449+ return (g,maybe inl bindingSpec gTmM, maybe specArg (Left . (`mkApps` gArgs) . bindingTerm) gTmM)
450+ else return (f,inl,specArg)
451+ _ -> return (f,inl,specArg)
452+ -- Create specialized functions
453+ let newBody = mkAbstraction (mkApps bodyTm (argVars ++ [specArg'])) (boundArgs ++ specBndrs)
454+ newf <- force <$> mkFunction (varName fId) sp inl' newBody
455+ -- Remember specialization
456+ MVar. putMVar specHistMV (extendUniqMapWith f 1 (+) specHist)
457+ -- use specialized function
458+ let newCache = Map. insert (f, argLen, specAbs) newf specCache
459+ let newExpr = mkApps (mkTicks (Var newf) ticks) (args ++ specVars)
460+ changed (newCache, newExpr)
461+ Nothing -> return (specCache, e)
458462 where
459463 collectBndrsMinusApps :: Term -> [Name a ]
460464 collectBndrsMinusApps = reverse . go []
0 commit comments