Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,16 @@
within a binding.
* Add `FuseTypes` annotation for making types locally fusible within a
specific binding.
* Add `NoFuseTypes` annotation for overriding `Fuse` data type annotation
* Add `NoFuse` annotation for disabling any `Fuse` data type annotation
inside a binding.
* Add `NoFuseTypes` annotation for disabling `Fuse` annotation for specific
types within a binding.
* Add `MaxCoreSize` annotation to report if core size of a binding
exceeds a certain threashold.
* Add `DumpCore` annotation to write the optimized core of a binding to a
file.
* Add `DumpCorePasses` annotation to write the core of a binding to a file
after every Core-to-core pass.

## 0.1.0

Expand Down
91 changes: 78 additions & 13 deletions src/Fusion/Plugin/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ module Fusion.Plugin.Types
Fuse(..)
, FuseTypes(..)
, NoFuseTypes(..)
, NoFuse(..)

-- ** Inspection Annotations
-- | Annotations to find fusion violations.
Expand All @@ -35,6 +36,7 @@ module Fusion.Plugin.Types

-- ** Debugging Annotations
, DumpCore(..)
, DumpCorePasses(..)
)
where

Expand Down Expand Up @@ -83,7 +85,8 @@ newtype FuseTypes = FuseTypes [Name]
-- | A GHC annotation attached to a specific top level binding (via an @ANN@
-- pragma on the binding, not on a type) that makes each of the listed types
-- behave as if it were /not/ annotated with 'Fuse', but /only/ for the purpose
-- of inlining within that one binding -- not anywhere else in the module.
-- of inlining within that one binding -- not anywhere else in the module. This
-- is applicable for any nested bindings within the scope of that binding.
--
-- This is the local override of 'Fuse' (and of 'FuseTypes'). Whereas @{-\# ANN
-- type Step Fuse #-}@ marks @Step@ as fusible everywhere it is used, @{-\# ANN
Expand All @@ -100,6 +103,17 @@ newtype FuseTypes = FuseTypes [Name]
newtype NoFuseTypes = NoFuseTypes [Name]
deriving (Eq, Data)

-- | A GHC annotation attached to a specific top level binding (via an @ANN@
-- pragma on the binding, not on a type) that disables forced inlining of that
-- binding and any nested bindings within the scope of that binding altogether,
-- regardless of which types are involved.
--
-- @
-- {-\# ANN myFunc NoFuse #-}
-- @
data NoFuse = NoFuse
deriving (Eq, Data)

-- | A GHC annotation attached to a specific top level binding (via an @ANN@
-- pragma on the binding, not on a type) that requests a fusion report for just
-- that binding.
Expand All @@ -114,24 +128,36 @@ newtype NoFuseTypes = NoFuseTypes [Name]
-- {-\# ANN function1 (ForbidFused [] []) #-}
-- {-\# ANN function1a (ForbidFused [''Maybe] []) #-}
-- {-\# ANN function1b (ForbidFused [''Maybe] [''Step]) #-}
-- {-\# ANN function2 (ForbidTypes [''Maybe]) #-}
-- {-\# ANN function3 (PermitTypes [''Int, ''IO]) #-}
-- {-\# ANN function2 (ForbidBoxedUse [''Maybe]) #-}
-- {-\# ANN function3 (PermitBoxedUse [''Int, ''IO]) #-}
-- {-\# ANN function4 (PermitPatternMatches [''Int, ''IO]) #-}
-- {-\# ANN function5 (PermitAllocations [''Int, ''IO]) #-}
-- @
data InspectTypes
= ForbidFused [Name] [Name]
-- ^ Report occurrences of every 'Fuse'-annotated type found in the binding
-- -- plus any types named in the first (forbid) list, minus any types
-- named in the second (allow) list. A name present in both lists is
-- allowed.
| ForbidTypes [Name]
| ForbidBoxedUse [Name]
-- ^ Blocklist: report occurrences of exactly the named types/constructors
-- found anywhere in the binding, regardless of whether they carry a 'Fuse'
-- annotation. Everything else in core is fine.
| PermitTypes [Name]
| PermitBoxedUse [Name]
-- ^ Allowlist: report occurrences of literally every type/constructor
-- found in the binding -- a general "boxing detector", not limited to
-- 'Fuse'-annotated types -- except the named types, which may appear
-- freely.
| PermitPatternMatches [Name]
-- ^ Like 'PermitBoxedUse' but only reports occurrences in a scrutinizing
-- (pattern-match, i.e. @case@) position -- a value being deconstructed --
-- ignoring constructing positions. Reports every type pattern-matched in
-- the binding except the named types, which may appear freely.
| PermitAllocations [Name]
-- ^ Like 'PermitBoxedUse' but only reports occurrences in a constructing
-- (allocating) position -- a value being built -- ignoring scrutinizing
-- positions. Reports every type constructed in the binding except the
-- named types, which may appear freely.
deriving (Eq, Data)

-- | A GHC annotation attached to a specific top level binding (via an @ANN@
Expand Down Expand Up @@ -180,15 +206,16 @@ newtype MaxCoreSize = MaxCoreSize Int
-- pragma on the binding) that makes the plugin dump the optimized Core of that
-- binding, after all fusion-plugin passes have run, to a file.
--
-- The Core is written to a file under the @fusion-plugin-output@ directory, in
-- a subdirectory named after the package being compiled. For example, a
-- binding @myFunction@ in module @Data.Stream@ of package @my-pkg@ is written
-- to
-- @fusion-plugin-output\/my-pkg\/Data.Stream.myFunction.dump-simpl@.
-- The Core is written to GHC's dump directory (as set by @-dumpdir@) if one is
-- set, otherwise to a per-package subdirectory of @fusion-plugin-output@. For
-- example, a binding @myFunction@ in module @Data.Stream@ of package @my-pkg@
-- is written to @\<dump-dir\>\/Data.Stream.myFunction.dump-simpl@, or to
-- @fusion-plugin-output\/my-pkg\/Data.Stream.myFunction.dump-simpl@ when no
-- dump directory is set.
--
-- Note that the output directory is created in the current directory from
-- where GHC is invoked, when building with cabal it is usually the directory
-- in which the cabal file of the package resides.
-- Note that the @fusion-plugin-output@ fallback directory is created in the
-- current directory from where GHC is invoked; when building with cabal that is
-- usually the directory in which the cabal file of the package resides.
--
-- This is useful for inspecting the final Core of a hot binding without having
-- to wade through the Core of the entire module.
Expand All @@ -198,3 +225,41 @@ newtype MaxCoreSize = MaxCoreSize Int
-- @
data DumpCore = DumpCore
deriving (Eq, Data)

-- | A GHC annotation attached to a specific top level binding (via an @ANN@
-- pragma on the binding) that makes the plugin dump the Core of that binding
-- /after every Core-to-core pass/, each to its own file. This is the
-- per-binding counterpart of the @dump-core@ plugin option: whereas
-- @dump-core@ dumps the Core of the /whole module/ after each pass,
-- 'DumpCorePasses' dumps only the annotated binding (and the closure of top
-- level bindings it reaches).
--
-- The files are written to the same directory and with the same
-- @\<module\>.@ prefix as the 'DumpCore' annotation output -- GHC's dump
-- directory (as set by @-dumpdir@) if one is set, otherwise a per-package
-- subdirectory of @fusion-plugin-output@ -- so all of a module's fusion-plugin
-- dumps cluster together under one prefix. Each file is named
-- @\<module\>.\<binder\>.\<NN-pass\>.dump-simpl@, where the per-pass suffix (a
-- two digit pass counter and the pass name) is the same one the @dump-core@
-- option uses for its per-pass files. For example, a binding @myFunction@ in
-- module @Data.Stream@ of package @my-pkg@ produces one file per pass:
--
-- @
-- -- with @-dumpdir dir@:
-- dir\/Data.Stream.myFunction.00-Initial.dump-simpl
-- dir\/Data.Stream.myFunction.01-After-...\.dump-simpl
-- ...
-- -- otherwise:
-- fusion-plugin-output\/my-pkg\/Data.Stream.myFunction.00-Initial.dump-simpl
-- ...
-- @
--
-- This is useful for understanding how the Core of a single binding evolves
-- across the optimizer pipeline, without wading through the Core of the entire
-- module at every pass.
--
-- @
-- {-\# ANN myFunction DumpCorePasses #-}
-- @
data DumpCorePasses = DumpCorePasses
deriving (Eq, Data)
Loading