X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=c%CE%BBash%2FCLasH%2FNormalize.hs;h=40eab93c3787e27d9b599d939aeccd8e77264352;hb=875c091f99d69f5c6921dd7defbbd7a4c9c207ac;hp=4366949a524cb6bbb28e0a84baad08cb8e214fc7;hpb=cda7d41d556f8cc179cf29579b213dc480ab5dba;p=matthijs%2Fmaster-project%2Fc%CE%BBash.git diff --git "a/c\316\273ash/CLasH/Normalize.hs" "b/c\316\273ash/CLasH/Normalize.hs" index 4366949..40eab93 100644 --- "a/c\316\273ash/CLasH/Normalize.hs" +++ "b/c\316\273ash/CLasH/Normalize.hs" @@ -64,8 +64,10 @@ etatop = notappargs ("eta", eta) -- β-reduction -------------------------------- beta, betatop :: Transform --- Substitute arg for x in expr -beta (App (Lam x expr) arg) = change $ substitute [(x, arg)] expr +-- Substitute arg for x in expr. For value lambda's, also clone before +-- substitution. +beta (App (Lam x expr) arg) | CoreSyn.isTyVar x = setChanged >> substitute x arg expr + | otherwise = setChanged >> substitute_clone x arg expr -- Propagate the application into the let beta (App (Let binds expr) arg) = change $ Let binds (App expr arg) -- Propagate the application into each of the alternatives @@ -303,49 +305,75 @@ letmergetop = everywhere ("letmerge", letmerge) -} -------------------------------- --- Function inlining +-- Non-representable binding inlining -------------------------------- --- Remove a = B bindings, with B :: a -> b, or B :: forall x . T, from let --- expressions everywhere. This means that any value that still needs to be --- applied to something else (polymorphic values need to be applied to a --- Type) will be inlined, and will eventually be applied to all their --- arguments. +-- Remove a = B bindings, with B of a non-representable type, from let +-- expressions everywhere. This means that any value that we can't generate a +-- signal for, will be inlined and hopefully turned into something we can +-- represent. -- -- This is a tricky function, which is prone to create loops in the -- transformations. To fix this, we make sure that no transformation will --- create a new let binding with a function type. These other transformations --- will just not work on those function-typed values at first, but the other --- transformations (in particular β-reduction) should make sure that the type --- of those values eventually becomes primitive. +-- create a new let binding with a non-representable type. These other +-- transformations will just not work on those function-typed values at first, +-- but the other transformations (in particular β-reduction) should make sure +-- that the type of those values eventually becomes representable. inlinenonreptop :: Transform inlinenonreptop = everywhere ("inlinenonrep", inlinebind ((Monad.liftM not) . isRepr . snd)) +-------------------------------- +-- Top level function inlining +-------------------------------- +-- This transformation inlines top level bindings that have been generated by +-- the compiler and are really simple. Really simple currently means that the +-- normalized form only contains a single binding, which catches most of the +-- cases where a top level function is created that simply calls a type class +-- method with a type and dictionary argument, e.g. +-- fromInteger = GHC.Num.fromInteger (SizedWord D8) $dNum +-- which is later called using simply +-- fromInteger (smallInteger 10) +-- By inlining such calls to simple, compiler generated functions, we prevent +-- huge amounts of trivial components in the VHDL output, which the user never +-- wanted. We never inline user-defined functions, since we want to preserve +-- all structure defined by the user. Currently this includes all functions +-- that were created by funextract, since we would get loops otherwise. +-- +-- Note that "defined by the compiler" isn't completely watertight, since GHC +-- doesn't seem to set all those names as "system names", we apply some +-- guessing here. inlinetoplevel, inlinetopleveltop :: Transform -- Any system name is candidate for inlining. Never inline user-defined --- functions, to preserver structure. -inlinetoplevel expr@(Var f) | (Name.isSystemName . Id.idName) f = do +-- functions, to preserve structure. +inlinetoplevel expr@(Var f) | not $ isUserDefined f = do + norm <- isNormalizeable f -- See if this is a top level binding for which we have a body body_maybe <- Trans.lift $ getGlobalBind f - case body_maybe of - Just body -> do + if norm && Maybe.isJust body_maybe + then do -- Get the normalized version norm <- Trans.lift $ getNormalized f if needsInline norm - then - change norm + then do + -- Regenerate all uniques in the to-be-inlined expression + norm_uniqued <- Trans.lift $ genUniques norm + change norm_uniqued else return expr - -- No body, this is probably a local variable or builtin or external - -- function. - Nothing -> return expr + else + -- No body or not normalizeable. + return expr -- Leave all other expressions unchanged inlinetoplevel expr = return expr inlinetopleveltop = everywhere ("inlinetoplevel", inlinetoplevel) needsInline :: CoreExpr -> Bool --- Any function that just evaluates to another function, can be inlined ---needsInline (Var f) = True -needsInline _ = False +needsInline expr = case splitNormalized expr of + -- Inline any function that only has a single definition, it is probably + -- simple enough. This might inline some stuff that it shouldn't though it + -- will never inline user-defined functions (inlinetoplevel only tries + -- system names) and inlining should never break things. + (args, [bind], res) -> True + _ -> False -------------------------------- -- Scrutinee simplification @@ -423,7 +451,7 @@ casesimpl expr@(Case scrut b ty alts) = do -- binding containing a case expression. dobndr :: CoreBndr -> Int -> TransformMonad (CoreBndr, Maybe (CoreBndr, CoreExpr)) dobndr b i = do - repr <- isRepr (Var b) + repr <- isRepr b -- Is b wild (e.g., not a free var of expr. Since b is only in scope -- in expr, this means that b is unused if expr does not use it.) let wild = not (VarSet.elemVarSet b free_vars) @@ -637,6 +665,25 @@ funextract expr = return expr -- Perform this transform everywhere funextracttop = everywhere ("funextract", funextract) +-------------------------------- +-- Ensure that a function that just returns another function (or rather, +-- another top-level binder) is still properly normalized. This is a temporary +-- solution, we should probably integrate this pass with lambdasimpl and +-- letsimpl instead. +-------------------------------- +simplrestop expr@(Lam _ _) = return expr +simplrestop expr@(Let _ _) = return expr +simplrestop expr = do + local_var <- Trans.lift $ is_local_var expr + -- Don't extract values that are not representable, to prevent loops with + -- inlinenonrep + repr <- isRepr expr + if local_var || not repr + then + return expr + else do + id <- Trans.lift $ mkBinderFor expr "res" + change $ Let (NonRec id expr) (Var id) -------------------------------- -- End of transformations -------------------------------- @@ -645,7 +692,7 @@ funextracttop = everywhere ("funextract", funextract) -- What transforms to run? -transforms = [inlinetopleveltop, argproptop, funextracttop, etatop, betatop, castproptop, letremovesimpletop, letderectop, letremovetop, letsimpltop, letflattop, scrutsimpltop, casesimpltop, caseremovetop, inlinenonreptop, appsimpltop, letremoveunusedtop, castsimpltop, lambdasimpltop] +transforms = [inlinetopleveltop, argproptop, funextracttop, etatop, betatop, castproptop, letremovesimpletop, letderectop, letremovetop, letsimpltop, letflattop, scrutsimpltop, casesimpltop, caseremovetop, inlinenonreptop, appsimpltop, letremoveunusedtop, castsimpltop, lambdasimpltop, simplrestop] -- | Returns the normalized version of the given function. getNormalized :: @@ -669,9 +716,10 @@ normalizeExpr :: -> TranslatorSession CoreSyn.CoreExpr -- ^ The normalized expression normalizeExpr what expr = do + expr_uniqued <- genUniques expr -- Normalize this expression - trace (what ++ " before normalization:\n\n" ++ showSDoc ( ppr expr ) ++ "\n") $ return () - expr' <- dotransforms transforms expr + trace (what ++ " before normalization:\n\n" ++ showSDoc ( ppr expr_uniqued ) ++ "\n") $ return () + expr' <- dotransforms transforms expr_uniqued trace ("\n" ++ what ++ " after normalization:\n\n" ++ showSDoc ( ppr expr')) $ return () return expr'