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
82 changes: 47 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,58 +124,57 @@ function :: ...
### Inspecting Boxed Types within a Function

To verify elimination of certain types within a function annotate
the function with `InspectAllocations` (types constructed/allocated)
the function with `InspectConstructions` (types constructed/allocated)
and/or `InspectPatternMatches` (types scrutinized in a `case`). If
a violation is found the plugin will complain providing details of the
violation. When the `werror` plugin option is used it will fail the
compilation on violation.

The two annotation types are independent, so a single binding may carry
one of each to inspect both the constructing and the scrutinizing
position at once. All the examples below use the allocation variant;
position at once. All the examples below use the construction variant;
each has an analogous `...PatternMatches` counterpart.

```haskell
{-# LANGUAGE TemplateHaskellQuotes #-}

import Fusion.Plugin.Types (InspectAllocations(..), InspectPatternMatches(..))
import Fusion.Plugin.Types (InspectConstructions(..), InspectPatternMatches(..))
```

### Using `Fuse` Annotated as Baseline
The whole system reduces to four simple rules:

Complain if any `Fuse` annotated type is allocated in the function.
```haskell
{-# ANN function (ForbidFusedAllocations [] []) #-}
function1 :: ...
```

Also forbid `Maybe` as well even though it isn't Fuse-annotated.
```haskell
{-# ANN function (ForbidFusedAllocations [''Maybe] []) #-}
function1a :: ...
```

Disallow `Maybe`, but explicitly allow `Step` even though it is Fuse-annotated
we allow it to be present in this binding.
```haskell
{-# ANN function (ForbidFusedAllocations [''Maybe] [''Step]) #-}
function1b :: ...
```
* A type explicitly listed in a `Forbid...` annotation is **always reported**
(forbidden).
* A type explicitly listed in a `Permit...` annotation is **always allowed**
(permitted), never reported.
* The `forbid-fused` plugin option **adds all `Fuse` annotated types to the
forbidden set**.
* By default unboxed types are implicitly in the permitted list. The
`inspect-unboxed` plugin option means **unboxed types are no longer
implicitly permitted**.

### Forbidding Only Selected Types

Disallow the specified types and allow the rest, irrespective of `Fuse`
annotation. To check both allocations and pattern matches, attach one
Disallow only the specified types and allow the rest, irrespective of the
`Fuse` annotation. To check both constructions and pattern matches, attach one
annotation of each type to the binding.
```haskell
{-# ANN function (ForbidAllocations [''Step]) #-}
{-# ANN function (ForbidConstructions [''Step]) #-}
{-# ANN function (ForbidPatternMatches [''Step]) #-}
function2 :: ...
```

Report the listed types only where they are allocated:
Additionally pass the `forbid-fused` plugin option to forbid all `Fuse`
annotated types too, using them as a baseline; the types named in the
annotation are then forbidden on top of them. With this option
`ForbidConstructions []` forbids exactly the `Fuse` annotated types.
```
ghc-options: -fplugin-opt=Fusion.Plugin:forbid-fused
```

Report the listed types only where they are constructed:
```haskell
{-# ANN function (ForbidAllocations [''Step]) #-}
{-# ANN function (ForbidConstructions [''Step]) #-}
```

Report the listed types only where they are pattern-matched:
Expand All @@ -186,23 +185,23 @@ Report the listed types only where they are pattern-matched:
### Permitting Only Selected Types

Allow only the specified types and disallow all others. To check both
allocations and pattern matches, attach one annotation of each type to the
constructions and pattern matches, attach one annotation of each type to the
binding.
```haskell
{-# ANN function (PermitAllocations [''Int, ''IO]) #-}
{-# ANN function (PermitConstructions [''Int, ''IO]) #-}
{-# ANN function (PermitPatternMatches [''Int, ''IO]) #-}
function3 :: ...
```

To report every allocated type used within a function:
To report every constructed type used within a function:
```haskell
{-# ANN function (PermitAllocations []) #-}
{-# ANN function (PermitConstructions []) #-}
function4 :: ...
```

Report every allocated type except the listed ones:
Report every constructed type except the listed ones:
```haskell
{-# ANN function (PermitAllocations [''Int, ''IO]) #-}
{-# ANN function (PermitConstructions [''Int, ''IO]) #-}
```

Report every pattern-matched type except the listed ones:
Expand All @@ -214,6 +213,19 @@ If any of the types in the permitted list is not actually found in the
binding, a warning is emitted so that stale entries can be removed from
the list.

### Including Unboxed Types in the Inspection

By default unboxed types (e.g. `Int#`, unboxed tuples and sums) are
implicitly considered in the `Permit...` list.

When `inspect-unboxed` plugin option is used, unboxed types are no longer
implicitly permitted, you will have to mention them explicitly in the permitted
list to allow them, forbidden list is not affected by this option.

```
ghc-options: -fplugin-opt=Fusion.Plugin:inspect-unboxed
```

### Inspecting type class dictionaries

To check the presence or absence of type classes in the Core of a binding,
Expand Down Expand Up @@ -302,7 +314,7 @@ violation.
### Detecting code bloat

To record the core size of every binding that carries a violation-causing
annotation (`InspectPatternMatches`, `InspectAllocations`, `InspectTypeClasses`
annotation (`InspectPatternMatches`, `InspectConstructions`, `InspectTypeClasses`
or `MaxCoreSize`) to a file, pass the `dump-core-sizes` option:
```
ghc-options: -fplugin-opt=Fusion.Plugin:dump-core-sizes
Expand Down Expand Up @@ -341,7 +353,7 @@ otherwise. Each pass adds a `<NN-pass-name>.dump-simpl` suffix, e.g.

`dump-core-if-annotated` option dumps the core of every binding
that carries a violation-causing annotation (`InspectPatternMatches`,
`InspectAllocations`, `InspectTypeClasses` or `MaxCoreSize`), without adding a
`InspectConstructions`, `InspectTypeClasses` or `MaxCoreSize`), without adding a
`DumpCore` annotation to each one:
```
ghc-options: -fplugin-opt=Fusion.Plugin:dump-core-if-annotated
Expand Down
2 changes: 1 addition & 1 deletion cabal.project
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ package fusion-plugin
source-repository-package
type: git
location: https://github.com/composewell/fusion-plugin-types.git
tag: 1f21d07917b62e1b9a5327f930bd31168441d505
tag: a74c4a229303b3df25d06853d80408c55b3e45e7
41 changes: 38 additions & 3 deletions src/Fusion/Plugin.hs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,25 @@ import Fusion.Plugin.Inspect
--
-- Verbosity levels @2@, @3@, @4@ can be used for more verbose output.
--
-- GHC option to make every @Forbid...@ annotation
-- ('Fusion.Plugin.Types.ForbidPatternMatches',
-- 'Fusion.Plugin.Types.ForbidConstructions') to implicitly forbid all
-- 'Fusion.Plugin.Types.Fuse' annotated types.
-- This does not affect the @Permit...@ annotations:
--
-- @
-- ghc-options: -fplugin-opt=Fusion.Plugin:forbid-fused
-- @
--
-- By default unboxed types (e.g. @Int#@, unboxed tuples and sums) are
-- implicitly in the permitted list. When `inspect-fused` plugin option is
-- enabled they are no longer implicitly permitted, they will now have to be
-- explictly mentioned in the permitted list to allow them.
--
-- @
-- ghc-options: -fplugin-opt=Fusion.Plugin:inspect-unboxed
-- @
--
-- To dump the core after each core to core transformation, pass the
-- following to your ghc-options:
--
Expand All @@ -152,8 +171,9 @@ import Fusion.Plugin.Inspect
-- Note: @dump-core@ does not work for GHC-9.0.x.
--
-- To record the optimized core size of every binding that carries a
-- violation-causing annotation ('InspectPatternMatches', 'InspectAllocations',
-- 'InspectTypeClasses' or 'MaxCoreSize') to a CSV file, pass the following:
-- violation-causing annotation ('InspectPatternMatches',
-- 'InspectConstructions', 'InspectTypeClasses' or 'MaxCoreSize') to a CSV
-- file, pass the following:
--
-- @
-- ghc-options: -fplugin-opt=Fusion.Plugin:dump-core-sizes
Expand All @@ -175,7 +195,7 @@ import Fusion.Plugin.Inspect
-- @
--
-- To dump the Core of every binding that carries a violation-causing
-- annotation ('InspectPatternMatches', 'InspectAllocations',
-- annotation ('InspectPatternMatches', 'InspectConstructions',
-- 'InspectTypeClasses' or 'MaxCoreSize'), pass the following:
--
-- @
Expand Down Expand Up @@ -230,6 +250,8 @@ defaultOptions = Options
, optionsVerbosityLevel = ReportSilent
, optionsWError = False
, optionsCsvAppend = False
, optionsForbidFused = False
, optionsInspectUnboxed = False
}

setDumpCore :: Monad m => Bool -> StateT ([CommandLineOption], Options) m ()
Expand Down Expand Up @@ -264,6 +286,17 @@ setCsvAppend val = do
(args, opts) <- get
put (args, opts { optionsCsvAppend = val })

setForbidFused :: Monad m => Bool -> StateT ([CommandLineOption], Options) m ()
setForbidFused val = do
(args, opts) <- get
put (args, opts { optionsForbidFused = val })

setInspectUnboxed
:: Monad m => Bool -> StateT ([CommandLineOption], Options) m ()
setInspectUnboxed val = do
(args, opts) <- get
put (args, opts { optionsInspectUnboxed = val })

setVerbosityLevel :: Monad m
=> ReportMode -> StateT ([CommandLineOption], Options) m ()
setVerbosityLevel val = do
Expand Down Expand Up @@ -295,6 +328,8 @@ parseOptions args =
"dump-core-if-violated" -> setDumpCoreIfViolated True
"werror" -> setWError True
"csv-append" -> setCsvAppend True
"forbid-fused" -> setForbidFused True
"inspect-unboxed" -> setInspectUnboxed True
"verbose=1" -> setVerbosityLevel ReportWarn
"verbose=2" -> setVerbosityLevel ReportVerbose
"verbose=3" -> setVerbosityLevel ReportVerbose1
Expand Down
2 changes: 2 additions & 0 deletions src/Fusion/Plugin/Common.hs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ data Options = Options
, optionsVerbosityLevel :: ReportMode
, optionsWError :: Bool
, optionsCsvAppend :: Bool
, optionsForbidFused :: Bool
, optionsInspectUnboxed :: Bool
} deriving Show

-- Checks whether a case alternative contains a type for which the given
Expand Down
Loading
Loading