[Git][ghc/ghc][master] Add -fpolymorphic-specialisation flag (off by default at all optimisation levels)
Marge Bot (@marge-bot)
gitlab at gitlab.haskell.org
Thu Jun 29 08:14:01 UTC 2023
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
9f01d14b by Matthew Pickering at 2023-06-29T04:13:41-04:00
Add -fpolymorphic-specialisation flag (off by default at all optimisation levels)
Polymorphic specialisation has led to a number of hard to diagnose
incorrect runtime result bugs (see #23469, #23109, #21229, #23445) so
this commit introduces a flag `-fpolymorhphic-specialisation` which
allows users to turn on this experimental optimisation if they are
willing to buy into things going very wrong.
Ticket #23469
- - - - -
7 changed files:
- compiler/GHC/Core/Opt/Specialise.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Session.hs
- docs/users_guide/9.8.1-notes.rst
- docs/users_guide/using-optimisation.rst
- testsuite/tests/simplCore/should_compile/T8331.stderr
- testsuite/tests/simplCore/should_compile/all.T
Changes:
=====================================
compiler/GHC/Core/Opt/Specialise.hs
=====================================
@@ -2490,6 +2490,12 @@ specArgFreeIds (SpecDict dx) = exprFreeIds dx
specArgFreeIds UnspecType = emptyVarSet
specArgFreeIds UnspecArg = emptyVarSet
+specArgFreeVars :: SpecArg -> VarSet
+specArgFreeVars (SpecType ty) = tyCoVarsOfType ty
+specArgFreeVars (SpecDict dx) = exprFreeVars dx
+specArgFreeVars UnspecType = emptyVarSet
+specArgFreeVars UnspecArg = emptyVarSet
+
isSpecDict :: SpecArg -> Bool
isSpecDict (SpecDict {}) = True
isSpecDict _ = False
@@ -2798,6 +2804,12 @@ non-dictionary bindings too.
Note [Specialising polymorphic dictionaries]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Note June 2023: This has proved to be quite a tricky optimisation to get right
+see (#23469, #23109, #21229, #23445) so it is now guarded by a flag
+`-fpolymorphic-specialisation`.
+
+
Consider
class M a where { foo :: a -> Int }
@@ -2988,14 +3000,23 @@ getTheta = fmap piTyBinderType . filter isInvisiblePiTyBinder . filter isAnonPiT
------------------------------------------------------------
-singleCall :: Id -> [SpecArg] -> UsageDetails
-singleCall id args
+singleCall :: SpecEnv -> Id -> [SpecArg] -> UsageDetails
+singleCall spec_env id args
= MkUD {ud_binds = emptyFDBs,
ud_calls = unitDVarEnv id $ CIS id $
unitBag (CI { ci_key = args
, ci_fvs = call_fvs }) }
where
- call_fvs = foldr (unionVarSet . specArgFreeIds) emptyVarSet args
+ call_fvs =
+ foldr (unionVarSet . free_var_fn) emptyVarSet args
+
+ free_var_fn =
+ if gopt Opt_PolymorphicSpecialisation (se_dflags spec_env)
+ then specArgFreeIds
+ else specArgFreeVars
+
+
+
-- specArgFreeIds: we specifically look for free Ids, not TyVars
-- see (MP1) in Note [Specialising polymorphic dictionaries]
--
@@ -3014,7 +3035,7 @@ mkCallUDs' env f args
| wantCallsFor env f -- We want it, and...
, not (null ci_key) -- this call site has a useful specialisation
= -- pprTrace "mkCallUDs: keeping" _trace_doc
- singleCall f ci_key
+ singleCall env f ci_key
| otherwise -- See also Note [Specialisations already covered]
= -- pprTrace "mkCallUDs: discarding" _trace_doc
=====================================
compiler/GHC/Driver/Flags.hs
=====================================
@@ -257,6 +257,7 @@ data GeneralFlag
| Opt_Specialise
| Opt_SpecialiseAggressively
| Opt_CrossModuleSpecialise
+ | Opt_PolymorphicSpecialisation
| Opt_InlineGenerics
| Opt_InlineGenericsAggressively
| Opt_StaticArgumentTransformation
=====================================
compiler/GHC/Driver/Session.hs
=====================================
@@ -2432,6 +2432,7 @@ fFlagsDeps = [
flagSpec "specialize-aggressively" Opt_SpecialiseAggressively,
flagSpec "cross-module-specialise" Opt_CrossModuleSpecialise,
flagSpec "cross-module-specialize" Opt_CrossModuleSpecialise,
+ flagSpec "polymorphic-specialisation" Opt_PolymorphicSpecialisation,
flagSpec "inline-generics" Opt_InlineGenerics,
flagSpec "inline-generics-aggressively" Opt_InlineGenericsAggressively,
flagSpec "static-argument-transformation" Opt_StaticArgumentTransformation,
=====================================
docs/users_guide/9.8.1-notes.rst
=====================================
@@ -174,11 +174,16 @@ Compiler
D(D2)
)
D = D1 | D2
-
+
This allows for changing the structure of a library without immediately breaking user code,
but instead being able to warn the user that a change in the library interface
will occur in the future.
+- Guard polymorphic specialisation behind the flag :ghc-flag:`-fpolymorphic-specialisation`.
+ This optimisation has led to a number of incorrect runtime result bugs, so we are disabling it
+ by default for now whilst we consider more carefully an appropiate fix.
+ (See :ghc-ticket:`23469`, :ghc-ticket:`23109`, :ghc-ticket:`21229`, :ghc-ticket:`23445`)
+
GHCi
~~~~
@@ -241,8 +246,8 @@ Runtime system
We use this functionality in GHCi to modify how some messages are displayed.
- The extensions fields of constructors of ``IE`` now take ``Maybe (WarningTxt p)``
- in ``GhcPs`` and ``GhcRn`` variants of the Syntax Tree.
- This represents the warning assigned to a certain export item,
+ in ``GhcPs`` and ``GhcRn`` variants of the Syntax Tree.
+ This represents the warning assigned to a certain export item,
which is used for :ref:`deprecated-exports`.
``ghc-heap`` library
=====================================
docs/users_guide/using-optimisation.rst
=====================================
@@ -1113,6 +1113,21 @@ as such you shouldn't need to set any of them explicitly. A flag
which they are called in this module. Note that specialisation must be
enabled (by ``-fspecialise``) for this to have any effect.
+.. ghc-flag:: -fpolymorphic-specialisation
+ :shortdesc: Allow specialisation to abstract over free type variables
+ :type: dynamic
+ :reverse: -fno-polymorphic-specialisation
+ :category:
+
+ :default: off
+
+ Warning, this feature is highly experimental and may lead to incorrect runtime
+ results. Use at your own risk (:ghc-ticket:`23469`, :ghc-ticket:`23109`, :ghc-ticket:`21229`, :ghc-ticket:`23445`).
+
+ Enable specialisation of function calls to known dictionaries with free type variables.
+ The created specialisation will abstract over the type variables free in the dictionary.
+
+
.. ghc-flag:: -flate-specialise
:shortdesc: Run a late specialisation pass
:type: dynamic
=====================================
testsuite/tests/simplCore/should_compile/T8331.stderr
=====================================
@@ -1,149 +1,5 @@
==================== Tidy Core rules ====================
-"SPEC $c*> @(ST s) @_"
- forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
- $fApplicativeReaderT_$c*> @(ST s) @r $dApplicative
- = ($fApplicativeReaderT2 @s @r)
- `cast` (forall (a :: <*>_N) (b :: <*>_N).
- <ReaderT r (ST s) a>_R
- %<'Many>_N ->_R <ReaderT r (ST s) b>_R
- %<'Many>_N ->_R <r>_R %<'Many>_N ->_R Sym (N:ST[0] <s>_N <b>_R)
- ; Sym (N:ReaderT[0] <*>_N <r>_R <ST s>_R <b>_N)
- :: Coercible
- (forall {a} {b}.
- ReaderT r (ST s) a -> ReaderT r (ST s) b -> r -> STRep s b)
- (forall {a} {b}.
- ReaderT r (ST s) a -> ReaderT r (ST s) b -> ReaderT r (ST s) b))
-"SPEC $c<$ @(ST s) @_"
- forall (@s) (@r) ($dFunctor :: Functor (ST s)).
- $fFunctorReaderT_$c<$ @(ST s) @r $dFunctor
- = ($fApplicativeReaderT6 @s @r)
- `cast` (forall (a :: <*>_N) (b :: <*>_N).
- <a>_R
- %<'Many>_N ->_R <ReaderT r (ST s) b>_R
- %<'Many>_N ->_R <r>_R %<'Many>_N ->_R Sym (N:ST[0] <s>_N <a>_R)
- ; Sym (N:ReaderT[0] <*>_N <r>_R <ST s>_R <a>_N)
- :: Coercible
- (forall {a} {b}. a -> ReaderT r (ST s) b -> r -> STRep s a)
- (forall {a} {b}. a -> ReaderT r (ST s) b -> ReaderT r (ST s) a))
-"SPEC $c<* @(ST s) @_"
- forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
- $fApplicativeReaderT_$c<* @(ST s) @r $dApplicative
- = ($fApplicativeReaderT1 @s @r)
- `cast` (forall (a :: <*>_N) (b :: <*>_N).
- <ReaderT r (ST s) a>_R
- %<'Many>_N ->_R <ReaderT r (ST s) b>_R
- %<'Many>_N ->_R <r>_R %<'Many>_N ->_R Sym (N:ST[0] <s>_N <a>_R)
- ; Sym (N:ReaderT[0] <*>_N <r>_R <ST s>_R <a>_N)
- :: Coercible
- (forall {a} {b}.
- ReaderT r (ST s) a -> ReaderT r (ST s) b -> r -> STRep s a)
- (forall {a} {b}.
- ReaderT r (ST s) a -> ReaderT r (ST s) b -> ReaderT r (ST s) a))
-"SPEC $c<*> @(ST s) @_"
- forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
- $fApplicativeReaderT9 @(ST s) @r $dApplicative
- = ($fApplicativeReaderT4 @s @r)
- `cast` (forall (a :: <*>_N) (b :: <*>_N).
- <ReaderT r (ST s) (a -> b)>_R
- %<'Many>_N ->_R <ReaderT r (ST s) a>_R
- %<'Many>_N ->_R <r>_R
- %<'Many>_N ->_R Sym (N:ST[0] <s>_N <b>_R)
- :: Coercible
- (forall {a} {b}.
- ReaderT r (ST s) (a -> b) -> ReaderT r (ST s) a -> r -> STRep s b)
- (forall {a} {b}.
- ReaderT r (ST s) (a -> b) -> ReaderT r (ST s) a -> r -> ST s b))
-"SPEC $c>> @(ST s) @_"
- forall (@s) (@r) ($dMonad :: Monad (ST s)).
- $fMonadReaderT1 @(ST s) @r $dMonad
- = $fMonadAbstractIOSTReaderT_$s$c>> @s @r
-"SPEC $c>>= @(ST s) @_"
- forall (@s) (@r) ($dMonad :: Monad (ST s)).
- $fMonadReaderT2 @(ST s) @r $dMonad
- = ($fMonadAbstractIOSTReaderT2 @s @r)
- `cast` (forall (a :: <*>_N) (b :: <*>_N).
- <ReaderT r (ST s) a>_R
- %<'Many>_N ->_R <a -> ReaderT r (ST s) b>_R
- %<'Many>_N ->_R <r>_R
- %<'Many>_N ->_R Sym (N:ST[0] <s>_N <b>_R)
- :: Coercible
- (forall {a} {b}.
- ReaderT r (ST s) a -> (a -> ReaderT r (ST s) b) -> r -> STRep s b)
- (forall {a} {b}.
- ReaderT r (ST s) a -> (a -> ReaderT r (ST s) b) -> r -> ST s b))
-"SPEC $cfmap @(ST s) @_"
- forall (@s) (@r) ($dFunctor :: Functor (ST s)).
- $fFunctorReaderT_$cfmap @(ST s) @r $dFunctor
- = ($fApplicativeReaderT7 @s @r)
- `cast` (forall (a :: <*>_N) (b :: <*>_N).
- <a -> b>_R
- %<'Many>_N ->_R <ReaderT r (ST s) a>_R
- %<'Many>_N ->_R <r>_R %<'Many>_N ->_R Sym (N:ST[0] <s>_N <b>_R)
- ; Sym (N:ReaderT[0] <*>_N <r>_R <ST s>_R <b>_N)
- :: Coercible
- (forall {a} {b}. (a -> b) -> ReaderT r (ST s) a -> r -> STRep s b)
- (forall {a} {b}.
- (a -> b) -> ReaderT r (ST s) a -> ReaderT r (ST s) b))
-"SPEC $cliftA2 @(ST s) @_"
- forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
- $fApplicativeReaderT_$cliftA2 @(ST s) @r $dApplicative
- = ($fApplicativeReaderT3 @s @r)
- `cast` (forall (a :: <*>_N) (b :: <*>_N) (c :: <*>_N).
- <a -> b -> c>_R
- %<'Many>_N ->_R <ReaderT r (ST s) a>_R
- %<'Many>_N ->_R <ReaderT r (ST s) b>_R
- %<'Many>_N ->_R <r>_R %<'Many>_N ->_R Sym (N:ST[0] <s>_N <c>_R)
- ; Sym (N:ReaderT[0] <*>_N <r>_R <ST s>_R <c>_N)
- :: Coercible
- (forall {a} {b} {c}.
- (a -> b -> c)
- -> ReaderT r (ST s) a -> ReaderT r (ST s) b -> r -> STRep s c)
- (forall {a} {b} {c}.
- (a -> b -> c)
- -> ReaderT r (ST s) a -> ReaderT r (ST s) b -> ReaderT r (ST s) c))
-"SPEC $cp1Applicative @(ST s) @_"
- forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
- $fApplicativeReaderT_$cp1Applicative @(ST s) @r $dApplicative
- = $fApplicativeReaderT_$s$fFunctorReaderT @s @r
-"SPEC $cp1Monad @(ST s) @_"
- forall (@s) (@r) ($dMonad :: Monad (ST s)).
- $fMonadReaderT_$cp1Monad @(ST s) @r $dMonad
- = $fApplicativeReaderT_$s$fApplicativeReaderT @s @r
-"SPEC $cpure @(ST s) @_"
- forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
- $fApplicativeReaderT_$cpure @(ST s) @r $dApplicative
- = ($fApplicativeReaderT5 @s @r)
- `cast` (forall (a :: <*>_N).
- <a>_R
- %<'Many>_N ->_R <r>_R %<'Many>_N ->_R Sym (N:ST[0] <s>_N <a>_R)
- ; Sym (N:ReaderT[0] <*>_N <r>_R <ST s>_R <a>_N)
- :: Coercible
- (forall {a}. a -> r -> STRep s a)
- (forall {a}. a -> ReaderT r (ST s) a))
-"SPEC $creturn @(ST s) @_"
- forall (@s) (@r) ($dMonad :: Monad (ST s)).
- $fMonadReaderT_$creturn @(ST s) @r $dMonad
- = ($fApplicativeReaderT5 @s @r)
- `cast` (forall (a :: <*>_N).
- <a>_R
- %<'Many>_N ->_R <r>_R %<'Many>_N ->_R Sym (N:ST[0] <s>_N <a>_R)
- ; Sym (N:ReaderT[0] <*>_N <r>_R <ST s>_R <a>_N)
- :: Coercible
- (forall {a}. a -> r -> STRep s a)
- (forall {a}. a -> ReaderT r (ST s) a))
-"SPEC $fApplicativeReaderT @(ST s) @_"
- forall (@s) (@r) ($dApplicative :: Applicative (ST s)).
- $fApplicativeReaderT @(ST s) @r $dApplicative
- = $fApplicativeReaderT_$s$fApplicativeReaderT @s @r
-"SPEC $fFunctorReaderT @(ST s) @_"
- forall (@s) (@r) ($dFunctor :: Functor (ST s)).
- $fFunctorReaderT @(ST s) @r $dFunctor
- = $fApplicativeReaderT_$s$fFunctorReaderT @s @r
-"SPEC $fMonadReaderT @(ST s) @_"
- forall (@s) (@r) ($dMonad :: Monad (ST s)).
- $fMonadReaderT @(ST s) @r $dMonad
- = $fMonadAbstractIOSTReaderT_$s$fMonadReaderT @s @r
"USPEC useAbstractMonad @(ReaderT Int (ST s))"
forall (@s)
($dMonadAbstractIOST :: MonadAbstractIOST (ReaderT Int (ST s))).
=====================================
testsuite/tests/simplCore/should_compile/all.T
=====================================
@@ -435,7 +435,7 @@ test('T21851', [grep_errmsg(r'case.*w\$sf') ], multimod_compile, ['T21851', '-O
# One module, T22097.hs, has OPTIONS_GHC -ddump-simpl
test('T22097', [grep_errmsg(r'case.*wgoEven') ], multimod_compile, ['T22097', '-O -dno-typeable-binds -dsuppress-uniques'])
-test('T13873', [ grep_errmsg(r'SPEC') ], compile, ['-O -ddump-rules'])
+test('T13873', [ grep_errmsg(r'SPEC') ], compile, ['-O -ddump-rules -fpolymorphic-specialisation'])
test('T22357', normal, compile, ['-O'])
test('T22471', normal, compile, ['-O'])
test('T22347', normal, compile, ['-O -fno-full-laziness'])
@@ -443,8 +443,8 @@ test('T22347a', normal, compile, ['-O2 -fno-full-laziness'])
# T17366: expecting to see a rule
# Rule fired: SPEC/T17366 f @(Tagged tag) @_ (T17366)
-test('T17366', normal, multimod_compile, ['T17366', '-O -v0 -ddump-rule-firings'])
-test('T17366_AR', [grep_errmsg(r'SPEC')], multimod_compile, ['T17366_AR', '-O -v0 -ddump-rule-firings'])
+test('T17366', normal, multimod_compile, ['T17366', '-O -v0 -ddump-rule-firings -fpolymorphic-specialisation'])
+test('T17366_AR', [grep_errmsg(r'SPEC')], multimod_compile, ['T17366_AR', '-O -v0 -ddump-rule-firings -fpolymorphic-specialisation'])
test('T22375', normal, compile, ['-O -ddump-simpl -dsuppress-uniques -dno-typeable-binds -dsuppress-unfoldings'])
# One module, T21851_2.hs, has OPTIONS_GHC -ddump-simpl
@@ -467,7 +467,7 @@ test('T22623', normal, multimod_compile, ['T22623', '-O -v0'])
test('T22662', normal, compile, [''])
test('T22725', normal, compile, ['-O'])
test('T22502', normal, compile, ['-O'])
-test('T22611', [when(wordsize(32), skip), grep_errmsg(r'\$salterF') ], compile, ['-O -ddump-simpl -dsuppress-uniques -dsuppress-all'])
+test('T22611', [when(wordsize(32), skip), grep_errmsg(r'\$salterF') ], compile, ['-O -ddump-simpl -dsuppress-uniques -dsuppress-all -fpolymorphic-specialisation'])
test('T22715_2', normal, multimod_compile, ['T22715_2', '-v0 -O -fspecialise-aggressively'])
test('T22802', normal, compile, ['-O'])
test('T15205', normal, compile, ['-O -ddump-simpl -dno-typeable-binds -dsuppress-uniques'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9f01d14b5bc1c73828b2b061206c45b84353620e
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9f01d14b5bc1c73828b2b061206c45b84353620e
You're receiving this email because of your account on gitlab.haskell.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20230629/726d3698/attachment-0001.html>
More information about the ghc-commits
mailing list