[Git][ghc/ghc][master] Tidy: Add flag to expose unfoldings if they take dictionary arguments.
Marge Bot (@marge-bot)
gitlab at gitlab.haskell.org
Sun May 12 17:39:58 UTC 2024
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
413217ba by Andreas Klebinger at 2024-05-12T13:39:11-04:00
Tidy: Add flag to expose unfoldings if they take dictionary arguments.
Add the flag `-fexpose-overloaded-unfoldings` to be able to control this
behaviour.
For ghc's boot libraries file size grew by less than 1% when it was
enabled. However I refrained from enabling it by default for now.
I've also added a section on specialization more broadly to the users
guide.
-------------------------
Metric Decrease:
MultiLayerModulesTH_OneShot
Metric Increase:
T12425
T13386
hard_hole_fits
-------------------------
- - - - -
11 changed files:
- compiler/GHC/Driver/Config/Tidy.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Iface/Tidy.hs
- docs/users_guide/9.12.1-notes.rst
- docs/users_guide/hints.rst
- docs/users_guide/using-optimisation.rst
- + testsuite/tests/simplCore/should_compile/ExposeOverloaded.hs
- + testsuite/tests/simplCore/should_compile/ExposeOverloaded.stderr
- testsuite/tests/simplCore/should_compile/T16038/Makefile
- testsuite/tests/simplCore/should_compile/all.T
Changes:
=====================================
compiler/GHC/Driver/Config/Tidy.hs
=====================================
@@ -36,6 +36,7 @@ initTidyOpts hsc_env = do
, opt_unfolding_opts = unfoldingOpts dflags
, opt_expose_unfoldings = if | gopt Opt_OmitInterfacePragmas dflags -> ExposeNone
| gopt Opt_ExposeAllUnfoldings dflags -> ExposeAll
+ | gopt Opt_ExposeOverloadedUnfoldings dflags -> ExposeOverloaded
| otherwise -> ExposeSome
, opt_expose_rules = not (gopt Opt_OmitInterfacePragmas dflags)
, opt_trim_ids = gopt Opt_OmitInterfacePragmas dflags
=====================================
compiler/GHC/Driver/Flags.hs
=====================================
@@ -328,6 +328,7 @@ data GeneralFlag
| Opt_IgnoreInterfacePragmas
| Opt_OmitInterfacePragmas
| Opt_ExposeAllUnfoldings
+ | Opt_ExposeOverloadedUnfoldings
| Opt_KeepAutoRules -- ^Keep auto-generated rules even if they seem to have become useless
| Opt_WriteInterface -- forces .hi files to be written even with -fno-code
| Opt_WriteHie -- generate .hie files
@@ -581,6 +582,7 @@ codeGenFlags = EnumSet.fromList
-- Flags that affect generated code
, Opt_ExposeAllUnfoldings
+ , Opt_ExposeOverloadedUnfoldings
, Opt_NoTypeableBinds
, Opt_Haddock
=====================================
compiler/GHC/Driver/Session.hs
=====================================
@@ -2442,6 +2442,7 @@ fFlagsDeps = [
flagSpec "error-spans" Opt_ErrorSpans,
flagSpec "excess-precision" Opt_ExcessPrecision,
flagSpec "expose-all-unfoldings" Opt_ExposeAllUnfoldings,
+ flagSpec "expose-overloaded-unfoldings" Opt_ExposeOverloadedUnfoldings,
flagSpec "keep-auto-rules" Opt_KeepAutoRules,
flagSpec "expose-internal-symbols" Opt_ExposeInternalSymbols,
flagSpec "external-dynamic-refs" Opt_ExternalDynamicRefs,
=====================================
compiler/GHC/Iface/Tidy.hs
=====================================
@@ -57,7 +57,7 @@ import GHC.Core.Tidy
import GHC.Core.Seq ( seqBinds )
import GHC.Core.Opt.Arity ( exprArity, typeArity, exprBotStrictness_maybe )
import GHC.Core.InstEnv
-import GHC.Core.Type ( Type, tidyTopType )
+import GHC.Core.Type
import GHC.Core.DataCon
import GHC.Core.TyCon
import GHC.Core.Class
@@ -87,6 +87,7 @@ import GHC.Types.Name.Cache
import GHC.Types.Avail
import GHC.Types.Tickish
import GHC.Types.TypeEnv
+import GHC.Tc.Utils.TcType (tcSplitNestedSigmaTys)
import GHC.Unit.Module
import GHC.Unit.Module.ModGuts
@@ -367,7 +368,9 @@ three places this is actioned:
data UnfoldingExposure
= ExposeNone -- ^ Don't expose unfoldings
- | ExposeSome -- ^ Only expose required unfoldings
+ | ExposeSome -- ^ Expose mandatory unfoldings and those meeting inlining thresholds.
+ | ExposeOverloaded -- ^ Expose unfoldings useful for inlinings and those which
+ -- which might be specialised. See Note [Exposing overloaded functions]
| ExposeAll -- ^ Expose all unfoldings
deriving (Show,Eq,Ord)
@@ -793,6 +796,10 @@ addExternal opts id
show_unfold = show_unfolding unfolding
never_active = isNeverActive (inlinePragmaActivation (inlinePragInfo idinfo))
loop_breaker = isStrongLoopBreaker (occInfo idinfo)
+ -- bottoming_fn: don't inline bottoming functions, unless the
+ -- RHS is very small or trivial (UnfWhen), in which case we
+ -- may as well do so. For example, a cast might cancel with
+ -- the call site.
bottoming_fn = isDeadEndSig (dmdSigInfo idinfo)
-- Stuff to do with the Id's unfolding
@@ -800,30 +807,87 @@ addExternal opts id
-- In GHCi the unfolding is used by importers
show_unfolding (CoreUnfolding { uf_src = src, uf_guidance = guidance })
- = opt_expose_unfoldings opts == ExposeAll
+ = stable || profitable || explicitly_requested
+ where
+ -- Always expose things whose
+ -- source is an inline rule
+ stable = isStableSource src
+ -- Good for perf as it might inline
+ profitable
+ | never_active = False
+ | loop_breaker = False
+ | otherwise =
+ case guidance of
+ UnfWhen {} -> True
+ UnfIfGoodArgs {} -> not bottoming_fn
+ UnfNever -> False
+ -- Requested by the user through a flag.
+ explicitly_requested =
+ case opt_expose_unfoldings opts of
-- 'ExposeAll' says to expose all
-- unfoldings willy-nilly
-
- || isStableSource src -- Always expose things whose
- -- source is an inline rule
-
- || not dont_inline
- where
- dont_inline
- | never_active = True -- Will never inline
- | loop_breaker = True -- Ditto
- | otherwise = case guidance of
- UnfWhen {} -> False
- UnfIfGoodArgs {} -> bottoming_fn
- UnfNever {} -> True
- -- bottoming_fn: don't inline bottoming functions, unless the
- -- RHS is very small or trivial (UnfWhen), in which case we
- -- may as well do so For example, a cast might cancel with
- -- the call site.
+ ExposeAll -> True
+ -- Overloaded functions like @foo :: Bar a => ...@
+ -- See Note [Exposing overloaded functions]
+ ExposeOverloaded ->
+ not bottoming_fn && isOverloaded id
+ ExposeSome -> False
+ ExposeNone -> False
show_unfolding (DFunUnfolding {}) = True
show_unfolding _ = False
+isOverloaded :: Id -> Bool
+isOverloaded fn =
+ let fun_type = idType fn
+ -- TODO: The specialiser currently doesn't handle newtypes of the
+ -- form `newtype T x = T (C x => x)` well. So we don't bother
+ -- looking through newtypes for constraints.
+ -- (Newtypes are opaque to tcSplitNestedSigmaTys)
+ -- If the specialiser ever starts looking through newtypes properly
+ -- we might want to use a version of tcSplitNestedSigmaTys that looks
+ -- through newtypes.
+ (_ty_vars, constraints, _ty) = tcSplitNestedSigmaTys fun_type
+ -- NB: This will consider functions with only equality constraints overloaded.
+ -- While these sorts of constraints aren't currently useful for specialization
+ -- it's simpler to just include them.
+ in not . null $ constraints
+
+{- Note [Exposing overloaded functions]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+See also #13090 and #22942.
+
+The basic idea is that exposing only overloaded function is reasonably cheap
+but allows the specializer to fire more often as unfoldings for overloaded
+functions will generally be available. So we make the unfoldings of overloaded
+functions available when `-fexpose-overloaded-unfoldings is enabled.
+
+We use `tcSplitNestedSigmaTys` to see the constraints deep within in types like:
+ f :: Int -> forall a. Eq a => blah
+
+We could simply use isClassPred to check if any of the constraints responds to
+a class dictionary, but that would miss (perhaps obscure) opportunities
+like the one in the program below:
+
+ type family C a where
+ C Int = Eq Int
+ C Bool = Ord Bool
+
+
+ bar :: C a => a -> a -> Bool
+ bar = undefined
+ {-# SPECIALIZE bar :: Int -> Int -> Bool #-}
+
+GHC will specialize `bar` properly. However `C a =>` isn't recognized as class
+predicate since it's a type family in the definition. To ensure it's exposed
+anyway we allow for some false positives and simply expose all functions which
+have a constraint. This means we might expose more unhelpful unfoldings. But
+it seems like the better choice.
+
+Currently this option is off by default and has to be enabled manually. But
+we might change this in the future.
+-}
+
{-
************************************************************************
* *
=====================================
docs/users_guide/9.12.1-notes.rst
=====================================
@@ -44,6 +44,7 @@ and the migration guide.
The tradeoff is that calling `whoCreated` on top level value definitions like `foo` will be less informative.
+- A new flag ``-fexpose-overloaded-unfoldings`` has been added providing a lightweight alternative to ``-fexpose-all-unfoldings``.
GHCi
~~~~
=====================================
docs/users_guide/hints.rst
=====================================
@@ -366,6 +366,8 @@ extreme cases making it impossible to compile certain code.
For this reason GHC offers various ways to tune inlining
behaviour.
+.. _inlining-unfolding-creation:
+
Unfolding creation
~~~~~~~~~~~~~~~~~~
@@ -374,8 +376,9 @@ GHC requires the functions unfolding. The following flags can
be used to control unfolding creation. Making their creation more
or less likely:
-* :ghc-flag:`-fexpose-all-unfoldings`
* :ghc-flag:`-funfolding-creation-threshold=⟨n⟩`
+* :ghc-flag:`-fexpose-overloaded-unfoldings`
+* :ghc-flag:`-fexpose-all-unfoldings`
Inlining decisions
~~~~~~~~~~~~~~~~~~
@@ -414,6 +417,96 @@ There are also flags specific to the inlining of generics:
* :ghc-flag:`-finline-generics`
* :ghc-flag:`-finline-generics-aggressively`
+.. _control-specialization:
+
+Controlling specialization
+--------------------------------------------
+
+.. index::
+ single: specialize-pragma, controlling, specialization
+ single: unfolding, controlling
+
+GHC has the ability to optimize polymorphic code for specific type class instances
+at the use site. We call this specialisation and it's enabled through :ghc-flag:`-fspecialise`
+which is enabled by default at `-O1` or higher.
+
+GHC does this by creating a copy of the overloaded function, optimizing this copy
+for a given type class instance. Calls to the overloaded function using a statically
+known typeclass we created a specialization for will then be replaced by a call
+to the specialized version of the function.
+
+This can often be crucial to avoid overhead at runtime. However since this
+involves potentially making many copies of overloaded functions GHC doesn't
+always apply this optimization by default even in cases where it could do so.
+
+For GHC to be able to specialise, at a miminum the instance it specializes for
+must be known and the overloaded functions unfolding must be available.
+
+Commonly used flag/pragma combinations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+For applications which aren't very compute heavy the defaults are often good enough
+as they try to strike a reasonable balance between compile time and runtime.
+
+For libraries, if exported functions would benefit significantly from specialization,
+it's recommended to enable :ghc-flag:`-fexpose-overloaded-unfoldings` or manually
+attach INLINEABLE pragmas to performance relevant functions.
+This will ensure downstream users can specialize any overloaded functions exposed
+by the library if it's beneficial.
+
+If there are key parts of an application which rely on specialization for performance
+using `SPECIALIZE` pragmas in combination with either :ghc-flag:`-fexpose-overloaded-unfoldings`
+or `INLINEABLE` on key overloaded functions should allow for these functions to
+specialize without affecting overall compile times too much.
+
+For compute heavy code reliant on elimination of as much overhead as possible it's
+recommended to use a combination of :ghc-flag:`-fspecialise-aggressively` and
+:ghc-flag:`-fexpose-overloaded-unfoldings` or :ghc-flag:`-fexpose-all-unfoldings`.
+However this comes at a big cost to compile time.
+
+Unfolding availabiliy
+~~~~~~~~~~~~~~~~~~~~~
+
+Unfolding availabiliy is primarily determined by :ref:`these flags <inlining-unfolding-creation>`.
+
+Of particular interest for specialization are:
+
+* :ghc-flag:`-fexpose-all-unfoldings`
+* :ghc-flag:`-fexpose-overloaded-unfoldings`
+
+The former making *all* unfoldings available, potentially at high compile time cost.
+The later only makes available the functions that are overloaded. It's generally
+better to use :ghc-flag:`-fexpose-overloaded-unfoldings` over :ghc-flag:`-fexpose-all-unfoldings`
+when the goal is to ensure specializations.
+
+When does GHC generate specializations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Functions get considered for specialization either implicitly when GHC sees a use
+of an overloaded function used with concrete typeclass instances or explicitly
+when a user requests it through pragmas, see :ref:`specialize-pragma` and :ref:`specialize-instance-pragma`.
+
+The specializer then checks a number of conditions *in order* to decide weither or not
+specialization should happen. Below is a best effort of the list of conditions GHC checks
+currently.
+
+* If any of the type class instances have type arguments and :ghc-flag:`-fpolymorphic-specialisation`
+ is not enabled (off by default) the function **won't** be specialised, otherwise
+* if the specialization was requested through a pragma GHC **will** try to create a specialization, otherwise
+* if the function is imported and:
+ + if the unfolding is not available the function **can't** be specialized, otherwise
+ + if :ghc-flag:`-fcross-module-specialise` is not enabled (enabled by `-O`) the function **won't** be specialised, otherwise
+ + if the flag is enabled, and the function has no INLINABLE/INLINE pragma it **won't** be specialised, otherwise
+* if :ghc-flag:`-fspecialise-aggressively` is enabled GHC **will** try to create a specialization, otherwise
+* if the overloaded function is defined in the current module, and all type class instances
+ are statically known it **will** be specialized, otherwise
+* the function **won't** be specialized.
+
+Note that there are some cases in which GHC will try to specialize a function and fail.
+For example if a functions has an OPAQUE pragma or the unfolding is not available.
+
+Once a function is specialized GHC will create a rule, similar to these created by `RULE` pragmas
+which will fire at call sites involving known instances, replacing calls to the overloaded
+function with calls to the specialized function when possible.
.. _hints-os-memory:
=====================================
docs/users_guide/using-optimisation.rst
=====================================
@@ -519,9 +519,45 @@ as such you shouldn't need to set any of them explicitly. A flag
:default: off
- An experimental flag to expose all unfoldings, even for very large
- or recursive functions. This allows for all functions to be inlined
- while usually GHC would avoid inlining larger functions.
+ A flag to expose all unfoldings, even for very large or recursive functions.
+
+ However GHC will still use the usual heuristics to make inlining
+ and specialization choices. This means further measures are needed to
+ get benefits at use sites. Usually this involves one of:
+
+ * :ghc-flag:`-fspecialise-aggressively` to force as much specialization
+ as possible.
+ * `{-# SPECIALIZE #-}` pragmas to ensure specialization to specific types.
+ * Use of the magic `inline` function to force inlining.
+
+.. ghc-flag:: -fexpose-overloaded-unfoldings
+ :shortdesc: Expose unfoldings carrying constraints, even for very large or recursive functions.
+ :type: dynamic
+ :reverse: -fno-expose-overloaded-unfoldings
+ :category:
+
+ :default: off
+
+ This experimental flag is a slightly less heavy weight alternative
+ to :ghc-flag:`-fexpose-all-unfoldings`.
+
+ Instead of exposing all functions it only aims at exposing constrained functions.
+ This is intended to be used for cases where specialization is considered
+ crucial but :ghc-flag:`-fexpose-all-unfoldings` imposes too much compile
+ time cost.
+
+ Currently this won't expose unfoldings where a type class is hidden under a
+ newtype. That is for cases like: ::
+
+ newtype NT a = NT (Integral a => a)
+
+ foo :: NT a -> T1 -> TR
+
+ GHC won't recognise `foo` as specialisable and won't expose the unfolding
+ even with :ghc-flag:`-fexpose-overloaded-unfoldings` enabled.
+
+ All the other caveats about :ghc-flag:`-fexpose-overloaded-unfoldings`
+ still apply, so please see there for more details.
.. ghc-flag:: -ffloat-in
:shortdesc: Turn on the float-in transformation. Implied by :ghc-flag:`-O`.
@@ -1120,13 +1156,14 @@ as such you shouldn't need to set any of them explicitly. A flag
:default: off
- By default only type class methods and methods marked ``INLINABLE`` or
- ``INLINE`` are specialised. This flag will specialise any overloaded function
- regardless of size if its unfolding is available. This flag is not
- included in any optimisation level as it can massively increase code
- size. It can be used in conjunction with :ghc-flag:`-fexpose-all-unfoldings`
- if you want to ensure all calls are specialised.
+ This flag controls the specialisation of *imported* functions only. By default, an imported function
+ is only specialised if it is marked ``INLINEABLE`` or ``INLINE``.
+ But with :ghc-flag:`-fspecialise-aggressively`, an imported function is specialised
+ if its unfolding is available in the interface file. (Use :ghc-flag:`-fexpose-all-unfoldings`
+ or :ghc-flag:`-fexpose-overloaded-unfoldings` to ensure that the unfolding is put into the interface file.)
+ :ghc-flag:`-fspecialise-aggressively` is not included in any optimisation level
+ as it can massively increase code size.
.. ghc-flag:: -fcross-module-specialise
:shortdesc: Turn on specialisation of overloaded functions imported from
=====================================
testsuite/tests/simplCore/should_compile/ExposeOverloaded.hs
=====================================
@@ -0,0 +1,43 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# OPTIONS_GHC -O -fno-worker-wrapper -funfolding-creation-threshold=50 #-}
+{-# OPTIONS_GHC -dno-typeable-binds -fexpose-overloaded-unfoldings #-}
+
+module ExposeOverloaded where
+
+-- Will get an unfolding because of the Functor
+foo :: Functor f => Maybe (Maybe (Maybe (Maybe (Maybe (Maybe (f a))))))
+ -> (a -> b)
+ -> Maybe (Maybe (Maybe (Maybe (f b))))
+foo (Just (Just (Just (Just (Just (Just x)))))) f = Just $ Just $ Just $ Just $ fmap f x
+foo _ _ = Nothing
+
+type family C a where
+ C Int = Eq Int
+ C Bool = Ord Bool
+
+-- The Enum constraint should cause bars unfolding to be exposed.
+bar :: (C a, Enum a) => a -> a -> Bool
+bar a b = fromEnum (succ a) > fromEnum (pred . pred . pred . pred . pred $ b)
+
+-- But even if there is just *a* constraint that's not obviously a class the
+-- unfolding should be expose.
+fam :: (C a) => a -> Char -> Int -> (Bool, a)
+fam c a b = (fromEnum (succ a) > fromEnum (pred . pred . pred . pred . pred $ b), c)
+
+-- While the constraint itself is useless to the specialiser, this still gets exposed
+-- by -fexpose-overloaded-unfoldings since we check for the presence of a constraint
+-- and not it's usefulness.
+{-# NOINLINE eq_constraint #-}
+eq_constraint :: (a~b) => a -> b -> (a,b)
+eq_constraint a b = (a,b)
+
+newtype F t a = F {unF :: (Functor t => t a) }
+
+-- Will get NO unfolding currently since the class dictionary is hidden under the newtype.
+-- We might fix this eventually. But since the specializer doesn't handle this well
+-- this isn't important yet.
+baz :: Maybe (Maybe (Maybe (Maybe (Maybe (Maybe (F t a))))))
+ -> (a -> b)
+ -> Maybe (Maybe (Maybe (Maybe (F t b))))
+baz (Just (Just (Just (Just (Just (Just (x))))))) f = Just $ Just $ Just $ Just $ F $ fmap f (unF x)
+baz _ _ = Nothing
\ No newline at end of file
=====================================
testsuite/tests/simplCore/should_compile/ExposeOverloaded.stderr
=====================================
@@ -0,0 +1,254 @@
+
+==================== Tidy Core ====================
+Result size of Tidy Core
+ = {terms: 186, types: 410, coercions: 10, joins: 0/0}
+
+-- RHS size: {terms: 6, types: 8, coercions: 3, joins: 0/0}
+unF :: forall (t :: * -> *) a. F t a -> Functor t => t a
+[GblId[[RecSel]],
+ Arity=2,
+ Str=<1C(1,L)><L>,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=ALWAYS_IF(arity=2,unsat_ok=True,boring_ok=True)}]
+unF
+ = \ (@(t_aPM :: * -> *))
+ (@a_aPN)
+ (ds_d14Y :: F t_aPM a_aPN)
+ ($dFunctor_aPP :: Functor t_aPM) ->
+ (ds_d14Y
+ `cast` (ExposeOverloaded.N:F[0] <t_aPM>_N <a_aPN>_N
+ :: F t_aPM a_aPN ~R# (Functor t_aPM => t_aPM a_aPN)))
+ $dFunctor_aPP
+
+-- RHS size: {terms: 44, types: 123, coercions: 0, joins: 0/0}
+foo
+ :: forall (f :: * -> *) a b.
+ Functor f =>
+ Maybe (Maybe (Maybe (Maybe (Maybe (Maybe (f a))))))
+ -> (a -> b) -> Maybe (Maybe (Maybe (Maybe (f b))))
+[GblId,
+ Arity=3,
+ Str=<MP(1C(1,C(1,L)),A)><1L><L>,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=NEVER}]
+foo
+ = \ (@(f_a11y :: * -> *))
+ (@a_a11z)
+ (@b_a11A)
+ ($dFunctor_a11B :: Functor f_a11y)
+ (ds_d14D
+ :: Maybe (Maybe (Maybe (Maybe (Maybe (Maybe (f_a11y a_a11z)))))))
+ (f1_aON :: a_a11z -> b_a11A) ->
+ case ds_d14D of {
+ Nothing ->
+ GHC.Internal.Maybe.Nothing
+ @(Maybe (Maybe (Maybe (f_a11y b_a11A))));
+ Just ds1_d14P ->
+ case ds1_d14P of {
+ Nothing ->
+ GHC.Internal.Maybe.Nothing
+ @(Maybe (Maybe (Maybe (f_a11y b_a11A))));
+ Just ds2_d14Q ->
+ case ds2_d14Q of {
+ Nothing ->
+ GHC.Internal.Maybe.Nothing
+ @(Maybe (Maybe (Maybe (f_a11y b_a11A))));
+ Just ds3_d14R ->
+ case ds3_d14R of {
+ Nothing ->
+ GHC.Internal.Maybe.Nothing
+ @(Maybe (Maybe (Maybe (f_a11y b_a11A))));
+ Just ds4_d14S ->
+ case ds4_d14S of {
+ Nothing ->
+ GHC.Internal.Maybe.Nothing
+ @(Maybe (Maybe (Maybe (f_a11y b_a11A))));
+ Just ds5_d14T ->
+ case ds5_d14T of {
+ Nothing ->
+ GHC.Internal.Maybe.Nothing
+ @(Maybe (Maybe (Maybe (f_a11y b_a11A))));
+ Just x_aOM ->
+ GHC.Internal.Maybe.Just
+ @(Maybe (Maybe (Maybe (f_a11y b_a11A))))
+ (GHC.Internal.Maybe.Just
+ @(Maybe (Maybe (f_a11y b_a11A)))
+ (GHC.Internal.Maybe.Just
+ @(Maybe (f_a11y b_a11A))
+ (GHC.Internal.Maybe.Just
+ @(f_a11y b_a11A)
+ (fmap
+ @f_a11y $dFunctor_a11B @a_a11z @b_a11A f1_aON x_aOM))))
+ }
+ }
+ }
+ }
+ }
+ }
+
+-- RHS size: {terms: 31, types: 20, coercions: 0, joins: 0/0}
+bar :: forall a. (C a, Enum a) => a -> a -> Bool
+[GblId,
+ Arity=4,
+ Str=<A><SP(MC(1,L),LC(S,L),A,SC(S,L),A,A,A,A)><L><L>,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=NEVER}]
+bar
+ = \ (@a_a10F)
+ _ [Occ=Dead]
+ ($dEnum_a10H :: Enum a_a10F)
+ (a1_aOV :: a_a10F)
+ (b_aOW :: a_a10F) ->
+ case fromEnum @a_a10F $dEnum_a10H (succ @a_a10F $dEnum_a10H a1_aOV)
+ of
+ { GHC.Types.I# x_a15W ->
+ case fromEnum
+ @a_a10F
+ $dEnum_a10H
+ (pred
+ @a_a10F
+ $dEnum_a10H
+ (pred
+ @a_a10F
+ $dEnum_a10H
+ (pred
+ @a_a10F
+ $dEnum_a10H
+ (pred @a_a10F $dEnum_a10H (pred @a_a10F $dEnum_a10H b_aOW)))))
+ of
+ { GHC.Types.I# y_a15Z ->
+ GHC.Prim.tagToEnum# @Bool (GHC.Prim.># x_a15W y_a15Z)
+ }
+ }
+
+-- RHS size: {terms: 46, types: 21, coercions: 0, joins: 0/0}
+fam :: forall a. C a => a -> Char -> Int -> (Bool, a)
+[GblId,
+ Arity=4,
+ Str=<A><L><ML><MP(1L)>,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=NEVER}]
+fam
+ = \ (@a_aZM)
+ _ [Occ=Dead]
+ (c_aP4 :: a_aZM)
+ (a1_aP5 :: Char)
+ (b_aP6 :: Int) ->
+ (case a1_aP5 of { GHC.Types.C# c#_a15M ->
+ case GHC.Prim.ord# c#_a15M of wild1_a15O {
+ __DEFAULT ->
+ case b_aP6 of { GHC.Types.I# x1_a15B ->
+ case x1_a15B of wild3_a15D {
+ __DEFAULT ->
+ GHC.Prim.tagToEnum#
+ @Bool
+ (GHC.Prim.>#
+ (GHC.Prim.+# wild1_a15O 1#) (GHC.Prim.-# wild3_a15D 5#));
+ -9223372036854775808# -> case GHC.Internal.Enum.$fEnumInt1 of {};
+ -9223372036854775807# -> case GHC.Internal.Enum.$fEnumInt1 of {};
+ -9223372036854775806# -> case GHC.Internal.Enum.$fEnumInt1 of {};
+ -9223372036854775805# -> case GHC.Internal.Enum.$fEnumInt1 of {};
+ -9223372036854775804# -> case GHC.Internal.Enum.$fEnumInt1 of {}
+ }
+ };
+ 1114111# -> case GHC.Internal.Enum.$fEnumChar2 of {}
+ }
+ },
+ c_aP4)
+
+-- RHS size: {terms: 8, types: 10, coercions: 0, joins: 0/0}
+eq_constraint [InlPrag=NOINLINE]
+ :: forall a b. (a ~ b) => a -> b -> (a, b)
+[GblId,
+ Arity=3,
+ Str=<A><L><L>,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=ALWAYS_IF(arity=3,unsat_ok=True,boring_ok=True)}]
+eq_constraint
+ = \ (@a_aZD)
+ (@b_aZE)
+ _ [Occ=Dead]
+ (a1_aP7 :: a_aZD)
+ (b1_aP8 :: b_aZE) ->
+ (a1_aP7, b1_aP8)
+
+-- RHS size: {terms: 45, types: 146, coercions: 7, joins: 0/0}
+baz
+ :: forall (t :: * -> *) a b.
+ Maybe (Maybe (Maybe (Maybe (Maybe (Maybe (F t a))))))
+ -> (a -> b) -> Maybe (Maybe (Maybe (Maybe (F t b))))
+[GblId, Arity=2, Str=<1L><L>, Unf=OtherCon []]
+baz
+ = \ (@(t_aYx :: * -> *))
+ (@a_aYy)
+ (@b_aYz)
+ (ds_d148
+ :: Maybe (Maybe (Maybe (Maybe (Maybe (Maybe (F t_aYx a_aYy)))))))
+ (f_aPa :: a_aYy -> b_aYz) ->
+ case ds_d148 of {
+ Nothing ->
+ GHC.Internal.Maybe.Nothing
+ @(Maybe (Maybe (Maybe (F t_aYx b_aYz))));
+ Just ds1_d14m ->
+ case ds1_d14m of {
+ Nothing ->
+ GHC.Internal.Maybe.Nothing
+ @(Maybe (Maybe (Maybe (F t_aYx b_aYz))));
+ Just ds2_d14n ->
+ case ds2_d14n of {
+ Nothing ->
+ GHC.Internal.Maybe.Nothing
+ @(Maybe (Maybe (Maybe (F t_aYx b_aYz))));
+ Just ds3_d14o ->
+ case ds3_d14o of {
+ Nothing ->
+ GHC.Internal.Maybe.Nothing
+ @(Maybe (Maybe (Maybe (F t_aYx b_aYz))));
+ Just ds4_d14p ->
+ case ds4_d14p of {
+ Nothing ->
+ GHC.Internal.Maybe.Nothing
+ @(Maybe (Maybe (Maybe (F t_aYx b_aYz))));
+ Just ds5_d14q ->
+ case ds5_d14q of {
+ Nothing ->
+ GHC.Internal.Maybe.Nothing
+ @(Maybe (Maybe (Maybe (F t_aYx b_aYz))));
+ Just x_aP9 ->
+ GHC.Internal.Maybe.Just
+ @(Maybe (Maybe (Maybe (F t_aYx b_aYz))))
+ (GHC.Internal.Maybe.Just
+ @(Maybe (Maybe (F t_aYx b_aYz)))
+ (GHC.Internal.Maybe.Just
+ @(Maybe (F t_aYx b_aYz))
+ (GHC.Internal.Maybe.Just
+ @(F t_aYx b_aYz)
+ ((\ ($dFunctor_aZi :: Functor t_aYx) ->
+ fmap
+ @t_aYx
+ $dFunctor_aZi
+ @a_aYy
+ @b_aYz
+ f_aPa
+ ((x_aP9
+ `cast` (ExposeOverloaded.N:F[0] <t_aYx>_N <a_aYy>_N
+ :: F t_aYx a_aYy
+ ~R# (Functor t_aYx => t_aYx a_aYy)))
+ $dFunctor_aZi))
+ `cast` (Sym (ExposeOverloaded.N:F[0] <t_aYx>_N <b_aYz>_N)
+ :: (Functor t_aYx => t_aYx b_aYz)
+ ~R# F t_aYx b_aYz)))))
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+
=====================================
testsuite/tests/simplCore/should_compile/T16038/Makefile
=====================================
@@ -6,5 +6,5 @@ T16038:
'$(TEST_HC)' $(TEST_HC_OPTS) -O -c A.hs-boot
'$(TEST_HC)' $(TEST_HC_OPTS) -O -c B.hs
# All `fEqHsExpr` bindings should be in one recursive group:
- '$(TEST_HC)' $(TEST_HC_OPTS) -O -c A.hs -ddump-simpl -dsuppress-all | \
+ '$(TEST_HC)' $(TEST_HC_OPTS) -O -c A.hs -ddump-simpl -dsuppress-all -fno-expose-overloaded-unfoldings | \
grep -e "^\$$fEqHsExpr" -e "Rec"
=====================================
testsuite/tests/simplCore/should_compile/all.T
=====================================
@@ -34,6 +34,10 @@ test('T7162', normal, compile, [''])
test('dfun-loop', normal, compile, [''])
test('strict-float', normal, compile, [''])
+
+# Check if overloaded functions get unfoldings
+test('ExposeOverloaded', [only_ways('[optasm]'), grep_errmsg('Unf=Unf')], compile, ['-ddump-simpl -dno-suppress-unfoldings'])
+
test('T3118', normal, compile, ['-Wno-overlapping-patterns'])
test('T4203', normal, compile, [''])
@@ -332,7 +336,7 @@ test('T18231', [ only_ways(['optasm']), grep_errmsg(r'^[\w\.]+ ::.*->.*') ], com
# Cast WW
test('T17673', [ only_ways(['optasm']), grep_errmsg(r'^\w+\.\$wf') ], compile, ['-ddump-simpl -dsuppress-uniques -dppr-cols=9999'])
test('T18078', [ only_ways(['optasm']), grep_errmsg(r'^\w+\.\$wf') ], compile, ['-ddump-simpl -dsuppress-uniques -dppr-cols=9999'])
-test('T18328', [ only_ways(['optasm']), grep_errmsg(r'Arity=') ], compile, ['-ddump-simpl -dsuppress-uniques'])
+test('T18328', [ only_ways(['optasm']), grep_errmsg(r'(Arity=2)',1) ], compile, ['-ddump-simpl -dsuppress-uniques'])
test('T18347', normal, compile, ['-dcore-lint -O'])
test('T18355', [ grep_errmsg(r'OneShot') ], compile, ['-O -ddump-simpl -dsuppress-uniques'])
test('T18399', normal, compile, ['-dcore-lint -O'])
@@ -363,7 +367,7 @@ test('T19599a', normal, compile, ['-O -ddump-rules'])
# Look for a specialisation rule for wimwam
test('T19672', normal, compile, ['-O2 -ddump-rules'])
-test('T20103', [ grep_errmsg(r'Arity') ], compile, ['-O -ddump-simpl -dsuppress-uniques'])
+test('T20103', [ grep_errmsg(r'(Arity=[0-9]*)',[1]) ], compile, ['-O -ddump-simpl -dsuppress-uniques'])
test('T19780', normal, compile, ['-O2'])
test('T19794', normal, compile, ['-O'])
test('T19890', [ grep_errmsg(r'= T19890.foo1') ], compile, ['-O -ddump-simpl'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/413217ba04b999313949b570a9386ca36e8ac82c
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/413217ba04b999313949b570a9386ca36e8ac82c
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/20240512/91b0cc17/attachment-0001.html>
More information about the ghc-commits
mailing list