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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ The whole system reduces to four simple rules:
(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
* The `inspect-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
Expand All @@ -164,12 +164,12 @@ annotation of each type to the binding.
function2 :: ...
```

Additionally pass the `forbid-fused` plugin option to forbid all `Fuse`
Additionally pass the `inspect-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
ghc-options: -fplugin-opt=Fusion.Plugin:inspect-fused
```

Report the listed types only where they are constructed:
Expand Down
87 changes: 67 additions & 20 deletions src/Fusion/Plugin.hs
Original file line number Diff line number Diff line change
Expand Up @@ -148,18 +148,40 @@ import Fusion.Plugin.Inspect
-- This does not affect the @Permit...@ annotations:
--
-- @
-- ghc-options: -fplugin-opt=Fusion.Plugin:forbid-fused
-- ghc-options: -fplugin-opt=Fusion.Plugin:inspect-fused
-- @
--
-- By default unboxed types (e.g. @Int#@, unboxed tuples and sums) are
-- implicitly in the permitted list. When `inspect-fused` plugin option is
-- implicitly in the permitted list. When `inspect-unboxed` 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
-- @
--
-- By default the plugin excludes unavoidable function /boundary/ crossings
-- from the reports, pattern matches on the function's arguments are not
-- reported as violations, similarly construction of the return values of a
-- function are not reported. The @inspect-boundaries@ option includes the
-- boundary matches and constructions as well:
--
-- @
-- ghc-options: -fplugin-opt=Fusion.Plugin:inspect-boundaries
-- @
--
-- To neutralize the 'Fusion.Plugin.Types.Fuse' annotation, making it a no-op,
-- pass the @fuse-ignore@ option:
--
-- @
-- ghc-options: -fplugin-opt=Fusion.Plugin:fuse-ignore
-- @
--
-- With this option the plugin does not force-inline anything, so the generated
-- code is left unchanged (as if the plugin were not enabled). The fusion
-- violation reports are still produced, which makes this useful for auditing
-- fusion using standard GHC compilation.
--
-- To dump the core after each core to core transformation, pass the
-- following to your ghc-options:
--
Expand Down Expand Up @@ -250,8 +272,10 @@ defaultOptions = Options
, optionsVerbosityLevel = ReportSilent
, optionsWError = False
, optionsCsvAppend = False
, optionsForbidFused = False
, optionsInspectFused = False
, optionsInspectUnboxed = False
, optionsInspectBoundaries = False
, optionsFuseIgnore = False
}

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

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

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

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

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

setVerbosityLevel :: Monad m
=> ReportMode -> StateT ([CommandLineOption], Options) m ()
setVerbosityLevel val = do
Expand Down Expand Up @@ -328,8 +364,10 @@ parseOptions args =
"dump-core-if-violated" -> setDumpCoreIfViolated True
"werror" -> setWError True
"csv-append" -> setCsvAppend True
"forbid-fused" -> setForbidFused True
"inspect-fused" -> setInspectFused True
"inspect-unboxed" -> setInspectUnboxed True
"inspect-boundaries" -> setInspectBoundaries True
"fuse-ignore" -> setFuseIgnore True
"verbose=1" -> setVerbosityLevel ReportWarn
"verbose=2" -> setVerbosityLevel ReportVerbose
"verbose=3" -> setVerbosityLevel ReportVerbose1
Expand Down Expand Up @@ -528,25 +566,34 @@ install args todos
-- expression directly.
--
-- TODO do not run simplify if we did not do anything in markInline phase.
--
-- When @fuse-ignore@ is set we neutralize the 'Fuse' annotation: the
-- force-inlining (markInline) and the follow-up gentle simplify passes
-- are skipped so codegen is left unchanged. Only the reporting pass
-- runs, so violations are still reported, but against GHC's ordinary
-- (un-force-inlined) baseline rather than the force-inlined one.
let markPasses
| optionsFuseIgnore options = []
| otherwise =
[ fusionMarkInline 1 ReportSilent True
, simplify
, fusionMarkInline 2 ReportSilent True
, simplify
, fusionMarkInline 3 ReportSilent True
, simplify
-- This lets us know what was left unfused after all the
-- inlining and case-of-case transformations.
, let mesg = "Check unfused (post inlining)"
in CoreDoPluginPass mesg
(fusionReport mesg ReportSilent False options)
]
return $
insertDumpPasses
(optionsVerbosityLevel options /= ReportSilent)
(optionsDumpCore options) dumpPassesRef $
insertAfterSimplPhase0
todos
[ fusionPluginMarker
, fusionMarkInline 1 ReportSilent True
, simplify
, fusionMarkInline 2 ReportSilent True
, simplify
, fusionMarkInline 3 ReportSilent True
, simplify
-- This lets us know what was left unfused after all the
-- inlining and case-of-case transformations.
, let mesg = "Check unfused (post inlining)"
in CoreDoPluginPass mesg
(fusionReport mesg ReportSilent False options)
]
(fusionPluginMarker : markPasses)
(let mesg = "Check unfused (final)"
report =
fusionReport
Expand Down
5 changes: 4 additions & 1 deletion src/Fusion/Plugin/Common.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module Fusion.Plugin.Common
, lookupBinderAnn
, subsumedBySameName
, binderClosure
, exprVarOccs

-- * Context / annotation traversal
, altsContainsAnn
Expand Down Expand Up @@ -182,8 +183,10 @@ data Options = Options
, optionsVerbosityLevel :: ReportMode
, optionsWError :: Bool
, optionsCsvAppend :: Bool
, optionsForbidFused :: Bool
, optionsInspectFused :: Bool
, optionsInspectUnboxed :: Bool
, optionsInspectBoundaries :: Bool
, optionsFuseIgnore :: Bool
} deriving Show

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