[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 4 commits: spec-constr: Lift argument limit for SPEC-marked functions
Marge Bot (@marge-bot)
gitlab at gitlab.haskell.org
Thu Sep 14 10:27:49 UTC 2023
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
56b403c9 by Ben Gamari at 2023-09-13T19:21:36-04:00
spec-constr: Lift argument limit for SPEC-marked functions
When the user adds a SPEC argument to a function, they are informing us
that they expect the function to be specialised. However, previously
this instruction could be preempted by the specialised-argument limit
(sc_max_args). Fix this.
This fixes #14003.
- - - - -
6840012e by Simon Peyton Jones at 2023-09-13T19:22:13-04:00
Fix eta reduction
Issue #23922 showed that GHC was bogusly eta-reducing a join point.
We should never eta-reduce (\x -> j x) to j, if j is a join point.
It is extremly difficult to trigger this bug. It took me 45 mins of
trying to make a small tests case, here immortalised as T23922a.
- - - - -
e2cafb83 by Andreas Klebinger at 2023-09-14T06:27:33-04:00
Profiling: Properly escape characters when using `-pj`.
There are some ways in which unusual characters like quotes or others
can make it into cost centre names. So properly escape these.
Fixes #23924
- - - - -
2d0980ca by Ellie Hermaszewska at 2023-09-14T06:27:36-04:00
Use clearer example variable names for bool eliminator
- - - - -
8 changed files:
- compiler/GHC/Core/Opt/Arity.hs
- compiler/GHC/Core/Opt/SpecConstr.hs
- libraries/base/Data/Bool.hs
- rts/ProfilerReportJson.c
- + testsuite/tests/simplCore/should_compile/T14003.hs
- + testsuite/tests/simplCore/should_compile/T14003.stderr
- + testsuite/tests/simplCore/should_compile/T23922a.hs
- testsuite/tests/simplCore/should_compile/all.T
Changes:
=====================================
compiler/GHC/Core/Opt/Arity.hs
=====================================
@@ -2328,18 +2328,6 @@ This test is made by `ok_fun` in tryEtaReduce.
* `/\a. \x. f @(Maybe a) x --> /\a. f @(Maybe a)`
See Note [Do not eta reduce PAPs] for why we insist on a trivial head.
-2. Type and dictionary abstraction. Regardless of whether 'f' is a value, it
- is always sound to reduce /type lambdas/, thus:
- (/\a -> f a) --> f
- Moreover, we always want to, because it makes RULEs apply more often:
- This RULE: `forall g. foldr (build (/\a -> g a))`
- should match `foldr (build (/\b -> ...something complex...))`
- and the simplest way to do so is eta-reduce `/\a -> g a` in the RULE to `g`.
-
- The type checker can insert these eta-expanded versions,
- with both type and dictionary lambdas; hence the slightly
- ad-hoc (all ok_lam bndrs)
-
Of course, eta reduction is not always sound. See Note [Eta reduction soundness]
for when it is.
@@ -2427,6 +2415,25 @@ case where `e` is trivial):
Here it's sound eta-reduce `\x. f x` to `f`, because `f` can't be bottom
after the `seq`. This turned up in #7542.
+ T. If the binders are all type arguments, it's always safe to eta-reduce,
+ regardless of the arity of f.
+ /\a b. f @a @b --> f
+
+2. Type and dictionary abstraction. Regardless of whether 'f' is a value, it
+ is always sound to reduce /type lambdas/, thus:
+ (/\a -> f a) --> f
+ Moreover, we always want to, because it makes RULEs apply more often:
+ This RULE: `forall g. foldr (build (/\a -> g a))`
+ should match `foldr (build (/\b -> ...something complex...))`
+ and the simplest way to do so is eta-reduce `/\a -> g a` in the RULE to `g`.
+
+ More debatably, we extend this to dictionary arguments too, because the type
+ checker can insert these eta-expanded versions, with both type and dictionary
+ lambdas; hence the slightly ad-hoc (all ok_lam bndrs). That is, we eta-reduce
+ \(d::Num a). f d --> f
+ regardless of f's arity. Its not clear whether or not this is important, and
+ it is not in general sound. But that's the way it is right now.
+
And here are a few more technical criteria for when it is *not* sound to
eta-reduce that are specific to Core and GHC:
@@ -2688,20 +2695,25 @@ tryEtaReduce rec_ids bndrs body eval_sd
ok_fun (App fun (Type {})) = ok_fun fun
ok_fun (Cast fun _) = ok_fun fun
ok_fun (Tick _ expr) = ok_fun expr
- ok_fun (Var fun_id) = is_eta_reduction_sound fun_id || all ok_lam bndrs
+ ok_fun (Var fun_id) = is_eta_reduction_sound fun_id
ok_fun _fun = False
---------------
-- See Note [Eta reduction soundness], this is THE place to check soundness!
- is_eta_reduction_sound fun =
- -- Don't eta-reduce in fun in its own recursive RHSs
- not (fun `elemUnVarSet` rec_ids) -- criterion (R)
- -- Check that eta-reduction won't make the program stricter...
- && (fun_arity fun >= incoming_arity -- criterion (A) and (E)
- || all_calls_with_arity incoming_arity) -- criterion (S)
- -- ... and that the function can be eta reduced to arity 0
- -- without violating invariants of Core and GHC
- && not (cantEtaReduceFun fun) -- criteria (L), (J), (W), (B)
+ is_eta_reduction_sound fun
+ | fun `elemUnVarSet` rec_ids -- Criterion (R)
+ = False -- Don't eta-reduce in fun in its own recursive RHSs
+
+ | cantEtaReduceFun fun -- Criteria (L), (J), (W), (B)
+ = False -- Function can't be eta reduced to arity 0
+ -- without violating invariants of Core and GHC
+
+ | otherwise
+ = -- Check that eta-reduction won't make the program stricter...
+ fun_arity fun >= incoming_arity -- Criterion (A) and (E)
+ || all_calls_with_arity incoming_arity -- Criterion (S)
+ || all ok_lam bndrs -- Criterion (T)
+
all_calls_with_arity n = isStrict (fst $ peelManyCalls n eval_sd)
-- See Note [Eta reduction based on evaluation context]
=====================================
compiler/GHC/Core/Opt/SpecConstr.hs
=====================================
@@ -519,14 +519,17 @@ This is all quite ugly; we ought to come up with a better design.
ForceSpecConstr arguments are spotted in scExpr' and scTopBinds which then set
sc_force to True when calling specLoop. This flag does four things:
- * Ignore specConstrThreshold, to specialise functions of arbitrary size
+(FS1) Ignore specConstrThreshold, to specialise functions of arbitrary size
(see scTopBind)
- * Ignore specConstrCount, to make arbitrary numbers of specialisations
+(FS2) Ignore specConstrCount, to make arbitrary numbers of specialisations
(see specialise)
- * Specialise even for arguments that are not scrutinised in the loop
+(FS3) Specialise even for arguments that are not scrutinised in the loop
(see argToPat; #4448)
- * Only specialise on recursive types a finite number of times
- (see is_too_recursive; #5550; Note [Limit recursive specialisation])
+(FS4) Only specialise on recursive types a finite number of times
+ (see sc_recursive; #5550; Note [Limit recursive specialisation])
+(FS5) Lift the restriction on the maximum number of arguments which
+ the optimisation will specialise.
+ (see `too_many_worker_args` in `callsToNewPats`; #14003)
The flag holds only for specialising a single binding group, and NOT
for nested bindings. (So really it should be passed around explicitly
@@ -1403,7 +1406,7 @@ scBind top_lvl env (NonRec bndr rhs) do_body
scBind top_lvl env (Rec prs) do_body
| isTopLevel top_lvl
, Just threshold <- sc_size (sc_opts env)
- , not force_spec
+ , not force_spec -- See Note [Forcing specialisation], point (FS1)
, not (all (couldBeSmallEnoughToInline (sc_uf_opts (sc_opts env)) threshold) rhss)
= -- Do no specialisation if the RHSs are too big
-- ToDo: I'm honestly not sure of the rationale of this size-testing, nor
@@ -1773,6 +1776,7 @@ specRec env body_calls rhs_infos
, sc_force env || isNothing (sc_count opts)
-- If both of these are false, the sc_count
-- threshold will prevent non-termination
+ -- See Note [Forcing specialisation], point (FS4) and (FS2)
, any ((> the_limit) . si_n_specs) spec_infos
= -- Give up on specialisation, but don't forget to include the rhs_usg
-- for the unspecialised function, since it may now be called
@@ -2399,8 +2403,11 @@ callsToNewPats env fn spec_info@(SI { si_specs = done_specs }) bndr_occs calls
non_dups = nubBy samePat new_pats
-- Remove ones that have too many worker variables
- small_pats = filterOut too_big non_dups
- too_big (CP { cp_qvars = vars, cp_args = args })
+ small_pats = filterOut too_many_worker_args non_dups
+
+ too_many_worker_args _
+ | sc_force env = False -- See (FS5) of Note [Forcing specialisation]
+ too_many_worker_args (CP { cp_qvars = vars, cp_args = args })
= not (isWorkerSmallEnough (sc_max_args $ sc_opts env) (valArgCount args) vars)
-- We are about to construct w/w pair in 'spec_one'.
-- Omit specialisation leading to high arity workers.
@@ -2693,6 +2700,7 @@ argToPat1 env in_scope val_env arg arg_occ _arg_str
-- In that case it counts as "interesting"
argToPat1 env in_scope val_env (Var v) arg_occ arg_str
| sc_force env || specialisableArgOcc arg_occ -- (a)
+ -- See Note [Forcing specialisation], point (FS3)
, is_value -- (b)
-- Ignoring sc_keen here to avoid gratuitously incurring Note [Reboxing]
-- So sc_keen focused just on f (I# x), where we have freshly-allocated
=====================================
libraries/base/Data/Bool.hs
=====================================
@@ -31,10 +31,10 @@ import GHC.Base
-- $setup
-- >>> import Prelude
--- | Case analysis for the 'Bool' type. @'bool' x y p@ evaluates to @x@
--- when @p@ is 'False', and evaluates to @y@ when @p@ is 'True'.
+-- | Case analysis for the 'Bool' type. @'bool' f t p@ evaluates to @f@
+-- when @p@ is 'False', and evaluates to @t@ when @p@ is 'True'.
--
--- This is equivalent to @if p then y else x@; that is, one can
+-- This is equivalent to @if p then t else f@; that is, one can
-- think of it as an if-then-else construct with its arguments
-- reordered.
--
@@ -49,14 +49,14 @@ import GHC.Base
-- >>> bool "foo" "bar" False
-- "foo"
--
--- Confirm that @'bool' x y p@ and @if p then y else x@ are
+-- Confirm that @'bool' f t p@ and @if p then t else f@ are
-- equivalent:
--
--- >>> let p = True; x = "bar"; y = "foo"
--- >>> bool x y p == if p then y else x
+-- >>> let p = True; f = "bar"; t = "foo"
+-- >>> bool f t p == if p then t else f
-- True
-- >>> let p = False
--- >>> bool x y p == if p then y else x
+-- >>> bool f t p == if p then t else f
-- True
--
bool :: a -> a -> Bool -> a
=====================================
rts/ProfilerReportJson.c
=====================================
@@ -17,36 +17,178 @@
#include <string.h>
-// I don't think this code is all that perf critical.
-// So we just allocate a new buffer each time around.
+// Including zero byte
+static size_t escaped_size(char const* str)
+{
+ size_t escaped_size = 0;
+ for (; *str != '\0'; str++) {
+ const unsigned char c = *str;
+ switch (c)
+ {
+ // quotation mark (0x22)
+ case '"':
+ {
+ escaped_size += 2;
+ break;
+ }
+
+ case '\\':
+ {
+ escaped_size += 2;
+ break;
+ }
+
+ // backspace (0x08)
+ case '\b':
+ {
+ escaped_size += 2;
+ break;
+ }
+
+ // formfeed (0x0c)
+ case '\f':
+ {
+ escaped_size += 2;
+ break;
+ }
+
+ // newline (0x0a)
+ case '\n':
+ {
+ escaped_size += 2;
+ break;
+ }
+
+ // carriage return (0x0d)
+ case '\r':
+ {
+ escaped_size += 2;
+ break;
+ }
+
+ // horizontal tab (0x09)
+ case '\t':
+ {
+ escaped_size += 2;
+ break;
+ }
+
+ default:
+ {
+ if (c <= 0x1f)
+ {
+ // print character c as \uxxxx
+ escaped_size += 6;
+ }
+ else
+ {
+ escaped_size ++;
+ }
+ break;
+ }
+ }
+ }
+ escaped_size++; // null byte
+
+ return escaped_size;
+}
+
static void escapeString(char const* str, char **buf)
{
char *out;
- size_t req_size; //Max required size for decoding.
- size_t in_size; //Input size, including zero.
-
- in_size = strlen(str) + 1;
- // The strings are generally small and short
- // lived so should be ok to just double the size.
- req_size = in_size * 2;
- out = stgMallocBytes(req_size, "writeCCSReportJson");
- *buf = out;
- // We provide an outputbuffer twice the size of the input,
- // and at worse double the output size. So we can skip
- // length checks.
+ size_t out_size; //Max required size for decoding.
+ size_t pos = 0;
+
+ out_size = escaped_size(str); //includes trailing zero byte
+ out = stgMallocBytes(out_size, "writeCCSReportJson");
for (; *str != '\0'; str++) {
- char c = *str;
- if (c == '\\') {
- *out = '\\'; out++;
- *out = '\\'; out++;
- } else if (c == '\n') {
- *out = '\\'; out++;
- *out = 'n'; out++;
- } else {
- *out = c; out++;
- }
+ const unsigned char c = *str;
+ switch (c)
+ {
+ // quotation mark (0x22)
+ case '"':
+ {
+ out[pos] = '\\';
+ out[pos + 1] = '"';
+ pos += 2;
+ break;
+ }
+
+ // reverse solidus (0x5c)
+ case '\\':
+ {
+ out[pos] = '\\';
+ out[pos+1] = '\\';
+ pos += 2;
+ break;
+ }
+
+ // backspace (0x08)
+ case '\b':
+ {
+ out[pos] = '\\';
+ out[pos + 1] = 'b';
+ pos += 2;
+ break;
+ }
+
+ // formfeed (0x0c)
+ case '\f':
+ {
+ out[pos] = '\\';
+ out[pos + 1] = 'f';
+ pos += 2;
+ break;
+ }
+
+ // newline (0x0a)
+ case '\n':
+ {
+ out[pos] = '\\';
+ out[pos + 1] = 'n';
+ pos += 2;
+ break;
+ }
+
+ // carriage return (0x0d)
+ case '\r':
+ {
+ out[pos] = '\\';
+ out[pos + 1] = 'r';
+ pos += 2;
+ break;
+ }
+
+ // horizontal tab (0x09)
+ case '\t':
+ {
+ out[pos] = '\\';
+ out[pos + 1] = 't';
+ pos += 2;
+ break;
+ }
+
+ default:
+ {
+ if (c <= 0x1f)
+ {
+ // print character c as \uxxxx
+ out[pos] = '\\';
+ sprintf(&out[pos + 1], "u%04x", (int)c);
+ pos += 6;
+ }
+ else
+ {
+ // all other characters are added as-is
+ out[pos++] = c;
+ }
+ break;
+ }
+ }
}
- *out = '\0';
+ out[pos++] = '\0';
+ assert(pos == out_size);
+ *buf = out;
}
static void
=====================================
testsuite/tests/simplCore/should_compile/T14003.hs
=====================================
@@ -0,0 +1,30 @@
+{-# OPTIONS_GHC -fspec-constr -fmax-worker-args=2 #-}
+
+-- | Ensure that functions with SPEC arguments are constructor-specialised
+-- even if their argument count exceeds -fmax-worker-args.
+module T14003 (pat1, pat2, pat3, pat4) where
+
+import GHC.Exts
+
+hi :: SPEC
+ -> Maybe Int
+ -> Maybe Int
+ -> Maybe Int
+ -> Int
+hi SPEC (Just x) (Just y) (Just z) = x+y+z
+hi SPEC (Just x) _ _ = hi SPEC (Just x) (Just 42) Nothing
+hi SPEC Nothing _ _ = 42
+
+pat1 :: Int -> Int
+pat1 n = hi SPEC (Just n) (Just 4) (Just 0)
+
+pat2 :: Int -> Int
+pat2 n = hi SPEC Nothing (Just n) Nothing
+
+pat3 :: Int -> Int
+pat3 n = hi SPEC Nothing Nothing (Just n)
+
+pat4 :: Int -> Int
+pat4 n = hi SPEC Nothing (Just n) (Just n)
+
+
=====================================
testsuite/tests/simplCore/should_compile/T14003.stderr
=====================================
@@ -0,0 +1,349 @@
+
+==================== SpecConstr ====================
+Result size of SpecConstr
+ = {terms: 179, types: 124, coercions: 0, joins: 0/0}
+
+-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
+$trModule_sF4 :: Addr#
+[LclId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=IF_ARGS [] 20 0}]
+$trModule_sF4 = "main"#
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+$trModule_sF5 :: GHC.Types.TrName
+[LclId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=IF_ARGS [] 10 10}]
+$trModule_sF5 = GHC.Types.TrNameS $trModule_sF4
+
+-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
+$trModule_sF6 :: Addr#
+[LclId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=IF_ARGS [] 30 0}]
+$trModule_sF6 = "T14003"#
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+$trModule_sF7 :: GHC.Types.TrName
+[LclId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=IF_ARGS [] 10 10}]
+$trModule_sF7 = GHC.Types.TrNameS $trModule_sF6
+
+-- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
+T14003.$trModule :: GHC.Types.Module
+[LclIdX,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=IF_ARGS [] 10 10}]
+T14003.$trModule = GHC.Types.Module $trModule_sF5 $trModule_sF7
+
+-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
+lvl_sFY :: Addr#
+[LclId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=IF_ARGS [] 100 0}]
+lvl_sFY = "T14003.hs:(14,1)-(16,39)|function hi"#
+
+-- RHS size: {terms: 2, types: 2, coercions: 0, joins: 0/0}
+lvl_sFp :: ()
+[LclId,
+ Str=b,
+ Cpr=b,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=False, ConLike=False, WorkFree=False, Expandable=False,
+ Guidance=NEVER}]
+lvl_sFp = Control.Exception.Base.patError @LiftedRep @() lvl_sFY
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+lvl_sFm :: Int
+[LclId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=IF_ARGS [] 10 10}]
+lvl_sFm = GHC.Types.I# 42#
+
+-- RHS size: {terms: 2, types: 1, coercions: 0, joins: 0/0}
+lvl_sFn :: Maybe Int
+[LclId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=IF_ARGS [] 10 10}]
+lvl_sFn = GHC.Maybe.Just @Int lvl_sFm
+
+Rec {
+-- RHS size: {terms: 8, types: 4, coercions: 0, joins: 0/0}
+$s$whi_sGi :: Int# -> Int -> Int#
+[LclId[StrictWorker([])], Arity=2, Str=<L><L>]
+$s$whi_sGi
+ = \ (sc_sGf :: Int#) (sc_sGe :: Int) ->
+ $whi_sFB
+ GHC.Types.SPEC
+ (GHC.Maybe.Just @Int sc_sGe)
+ lvl_sFn
+ (GHC.Maybe.Nothing @Int)
+
+-- RHS size: {terms: 11, types: 5, coercions: 0, joins: 0/0}
+$s$whi_sGa :: Int# -> Int# -> Int -> Int#
+[LclId[StrictWorker([])], Arity=3, Str=<L><L><L>]
+$s$whi_sGa
+ = \ (sc_sG5 :: Int#) (sc_sG4 :: Int#) (sc_sG3 :: Int) ->
+ case sc_sG3 of { I# x_aFe -> +# (+# x_aFe sc_sG4) sc_sG5 }
+
+-- RHS size: {terms: 2, types: 1, coercions: 0, joins: 0/0}
+$s$whi_sGb :: Int -> Int#
+[LclId[StrictWorker([])], Arity=1, Str=<L>]
+$s$whi_sGb = \ (sc_sG6 :: Int) -> 42#
+
+-- RHS size: {terms: 2, types: 1, coercions: 0, joins: 0/0}
+$s$whi_sGc :: Int -> Int#
+[LclId[StrictWorker([])], Arity=1, Str=<L>]
+$s$whi_sGc = \ (sc_sG7 :: Int) -> 42#
+
+-- RHS size: {terms: 3, types: 2, coercions: 0, joins: 0/0}
+$s$whi_sGd :: Int -> Int -> Int#
+[LclId[StrictWorker([])], Arity=2, Str=<L><L>]
+$s$whi_sGd = \ (sc_sG9 :: Int) (sc_sG8 :: Int) -> 42#
+
+-- RHS size: {terms: 47, types: 26, coercions: 0, joins: 0/0}
+$whi_sFB [InlPrag=[2], Occ=LoopBreaker]
+ :: SPEC -> Maybe Int -> Maybe Int -> Maybe Int -> Int#
+[LclId[StrictWorker([])],
+ Arity=4,
+ Str=<SL><SL><L><L>,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=IF_ARGS [30 30 80 62] 212 0},
+ RULES: "SC:$whi4" [2]
+ forall (sc_sGf :: Int#) (sc_sGe :: Int).
+ $whi_sFB GHC.Types.SPEC
+ (GHC.Maybe.Just @Int sc_sGe)
+ (GHC.Maybe.Just @Int (GHC.Types.I# sc_sGf))
+ (GHC.Maybe.Nothing @Int)
+ = $s$whi_sGi sc_sGf sc_sGe
+ "SC:$whi0" [2]
+ forall (sc_sG5 :: Int#) (sc_sG4 :: Int#) (sc_sG3 :: Int).
+ $whi_sFB GHC.Types.SPEC
+ (GHC.Maybe.Just @Int sc_sG3)
+ (GHC.Maybe.Just @Int (GHC.Types.I# sc_sG4))
+ (GHC.Maybe.Just @Int (GHC.Types.I# sc_sG5))
+ = $s$whi_sGa sc_sG5 sc_sG4 sc_sG3
+ "SC:$whi1" [2]
+ forall (sc_sG6 :: Int).
+ $whi_sFB GHC.Types.SPEC
+ (GHC.Maybe.Nothing @Int)
+ (GHC.Maybe.Just @Int sc_sG6)
+ (GHC.Maybe.Nothing @Int)
+ = $s$whi_sGb sc_sG6
+ "SC:$whi2" [2]
+ forall (sc_sG7 :: Int).
+ $whi_sFB GHC.Types.SPEC
+ (GHC.Maybe.Nothing @Int)
+ (GHC.Maybe.Nothing @Int)
+ (GHC.Maybe.Just @Int sc_sG7)
+ = $s$whi_sGc sc_sG7
+ "SC:$whi3" [2]
+ forall (sc_sG9 :: Int) (sc_sG8 :: Int).
+ $whi_sFB GHC.Types.SPEC
+ (GHC.Maybe.Nothing @Int)
+ (GHC.Maybe.Just @Int sc_sG8)
+ (GHC.Maybe.Just @Int sc_sG9)
+ = $s$whi_sGd sc_sG9 sc_sG8]
+$whi_sFB
+ = \ (ds_sFv [Dmd=SL] :: SPEC)
+ (ds_sFw [Dmd=SL] :: Maybe Int)
+ (ds_sFx :: Maybe Int)
+ (ds_sFy :: Maybe Int) ->
+ case ds_sFv of {
+ SPEC ->
+ case ds_sFw of wild_X2 [Dmd=A] {
+ Nothing -> 42#;
+ Just x_ayD [Dmd=S] ->
+ case ds_sFx of {
+ Nothing ->
+ $whi_sFB GHC.Types.SPEC wild_X2 lvl_sFn (GHC.Maybe.Nothing @Int);
+ Just y_ayE [Dmd=S!P(S)] ->
+ case ds_sFy of {
+ Nothing ->
+ $whi_sFB GHC.Types.SPEC wild_X2 lvl_sFn (GHC.Maybe.Nothing @Int);
+ Just z_ayF [Dmd=S!P(S)] ->
+ case x_ayD of { I# x_aFe ->
+ case y_ayE of { I# y_aFh ->
+ case z_ayF of { I# y_X7 -> +# (+# x_aFe y_aFh) y_X7 }
+ }
+ }
+ }
+ }
+ };
+ SPEC2 -> case lvl_sFp of {}
+ }
+end Rec }
+
+-- RHS size: {terms: 13, types: 8, coercions: 0, joins: 0/0}
+hi [InlPrag=[2]]
+ :: SPEC -> Maybe Int -> Maybe Int -> Maybe Int -> Int
+[LclId,
+ Arity=4,
+ Str=<SL><SL><L><L>,
+ Cpr=1,
+ Unf=Unf{Src=StableSystem, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=ALWAYS_IF(arity=4,unsat_ok=True,boring_ok=False)
+ Tmpl= \ (ds_sFv [Occ=Once1, Dmd=SL] :: SPEC)
+ (ds_sFw [Occ=Once1, Dmd=SL] :: Maybe Int)
+ (ds_sFx [Occ=Once1] :: Maybe Int)
+ (ds_sFy [Occ=Once1] :: Maybe Int) ->
+ case $whi_sFB ds_sFv ds_sFw ds_sFx ds_sFy of ww_sFS [Occ=Once1]
+ { __DEFAULT ->
+ GHC.Types.I# ww_sFS
+ }}]
+hi
+ = \ (ds_sFv [Dmd=SL] :: SPEC)
+ (ds_sFw [Dmd=SL] :: Maybe Int)
+ (ds_sFx :: Maybe Int)
+ (ds_sFy :: Maybe Int) ->
+ case $whi_sFB ds_sFv ds_sFw ds_sFx ds_sFy of ww_sFS { __DEFAULT ->
+ GHC.Types.I# ww_sFS
+ }
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+lvl_sFq :: Int
+[LclId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=IF_ARGS [] 10 10}]
+lvl_sFq = GHC.Types.I# 4#
+
+-- RHS size: {terms: 2, types: 1, coercions: 0, joins: 0/0}
+lvl_sFr :: Maybe Int
+[LclId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=IF_ARGS [] 10 10}]
+lvl_sFr = GHC.Maybe.Just @Int lvl_sFq
+
+-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
+lvl_sFs :: Int
+[LclId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=IF_ARGS [] 10 10}]
+lvl_sFs = GHC.Types.I# 0#
+
+-- RHS size: {terms: 2, types: 1, coercions: 0, joins: 0/0}
+lvl_sFt :: Maybe Int
+[LclId,
+ Unf=Unf{Src=<vanilla>, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=IF_ARGS [] 10 10}]
+lvl_sFt = GHC.Maybe.Just @Int lvl_sFs
+
+-- RHS size: {terms: 11, types: 3, coercions: 0, joins: 0/0}
+pat1 :: Int -> Int
+[LclIdX,
+ Arity=1,
+ Str=<L>,
+ Cpr=1,
+ Unf=Unf{Src=StableSystem, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=False)
+ Tmpl= \ (n_aBn [Occ=Once1] :: Int) ->
+ hi GHC.Types.SPEC (GHC.Maybe.Just @Int n_aBn) lvl_sFr lvl_sFt}]
+pat1
+ = \ (n_aBn :: Int) ->
+ case $whi_sFB
+ GHC.Types.SPEC (GHC.Maybe.Just @Int n_aBn) lvl_sFr lvl_sFt
+ of ww_sFS
+ { __DEFAULT ->
+ GHC.Types.I# ww_sFS
+ }
+
+-- RHS size: {terms: 11, types: 5, coercions: 0, joins: 0/0}
+pat2 :: Int -> Int
+[LclIdX,
+ Arity=1,
+ Str=<L>,
+ Cpr=1,
+ Unf=Unf{Src=StableSystem, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=False)
+ Tmpl= \ (n_aBo [Occ=Once1] :: Int) ->
+ hi
+ GHC.Types.SPEC
+ (GHC.Maybe.Nothing @Int)
+ (GHC.Maybe.Just @Int n_aBo)
+ (GHC.Maybe.Nothing @Int)}]
+pat2
+ = \ (n_aBo :: Int) ->
+ case $whi_sFB
+ GHC.Types.SPEC
+ (GHC.Maybe.Nothing @Int)
+ (GHC.Maybe.Just @Int n_aBo)
+ (GHC.Maybe.Nothing @Int)
+ of ww_sFS
+ { __DEFAULT ->
+ GHC.Types.I# ww_sFS
+ }
+
+-- RHS size: {terms: 11, types: 5, coercions: 0, joins: 0/0}
+pat3 :: Int -> Int
+[LclIdX,
+ Arity=1,
+ Str=<L>,
+ Cpr=1,
+ Unf=Unf{Src=StableSystem, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=False)
+ Tmpl= \ (n_aBp [Occ=Once1] :: Int) ->
+ hi
+ GHC.Types.SPEC
+ (GHC.Maybe.Nothing @Int)
+ (GHC.Maybe.Nothing @Int)
+ (GHC.Maybe.Just @Int n_aBp)}]
+pat3
+ = \ (n_aBp :: Int) ->
+ case $whi_sFB
+ GHC.Types.SPEC
+ (GHC.Maybe.Nothing @Int)
+ (GHC.Maybe.Nothing @Int)
+ (GHC.Maybe.Just @Int n_aBp)
+ of ww_sFS
+ { __DEFAULT ->
+ GHC.Types.I# ww_sFS
+ }
+
+-- RHS size: {terms: 12, types: 5, coercions: 0, joins: 0/0}
+pat4 :: Int -> Int
+[LclIdX,
+ Arity=1,
+ Str=<L>,
+ Cpr=1,
+ Unf=Unf{Src=StableSystem, TopLvl=True,
+ Value=True, ConLike=True, WorkFree=True, Expandable=True,
+ Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=False)
+ Tmpl= \ (n_aBq :: Int) ->
+ hi
+ GHC.Types.SPEC
+ (GHC.Maybe.Nothing @Int)
+ (GHC.Maybe.Just @Int n_aBq)
+ (GHC.Maybe.Just @Int n_aBq)}]
+pat4
+ = \ (n_aBq :: Int) ->
+ case $whi_sFB
+ GHC.Types.SPEC
+ (GHC.Maybe.Nothing @Int)
+ (GHC.Maybe.Just @Int n_aBq)
+ (GHC.Maybe.Just @Int n_aBq)
+ of ww_sFS
+ { __DEFAULT ->
+ GHC.Types.I# ww_sFS
+ }
+
+
+
=====================================
testsuite/tests/simplCore/should_compile/T23922a.hs
=====================================
@@ -0,0 +1,19 @@
+{-# OPTIONS_GHC -O -fworker-wrapper-cbv -dcore-lint -Wno-simplifiable-class-constraints #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+-- It is very tricky to tickle this bug in 9.6/9.8!
+-- (It came up in a complicated program due to Mikolaj.)
+--
+-- We need a join point, with only dictionary arguments
+-- whose RHS is just another join-point application, which
+-- can be eta-reduced.
+--
+-- The -fworker-wrapper-cbv makes a wrapper whose RHS looks eta-reducible.
+
+module T23922a where
+
+f :: forall a. Eq a => [a] -> Bool
+f x = let {-# NOINLINE j #-}
+ j :: Eq [a] => Bool
+ j = x==x
+ in j
=====================================
testsuite/tests/simplCore/should_compile/all.T
=====================================
@@ -254,6 +254,7 @@ test('T13658', normal, compile, ['-dcore-lint'])
test('T14779a', normal, compile, ['-dcore-lint'])
test('T14779b', normal, compile, ['-dcore-lint'])
test('T13708', normal, compile, [''])
+test('T14003', [only_ways(['optasm']), grep_errmsg('SC:')], compile, ['-ddump-spec-constr'])
# thunk should inline here, so check whether or not it appears in the Core
# (we skip profasm because it might not inline there)
@@ -498,3 +499,4 @@ test('T23567', [extra_files(['T23567A.hs'])], multimod_compile, ['T23567', '-O -
test('T22404', [only_ways(['optasm']), check_errmsg(r'let') ], compile, ['-ddump-simpl -dsuppress-uniques'])
test('T23864', normal, compile, ['-O -dcore-lint -package ghc -Wno-gadt-mono-local-binds'])
test('T23938', [extra_files(['T23938A.hs'])], multimod_compile, ['T23938', '-O -v0'])
+test('T23922a', normal, compile, ['-O'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/b56e0cd300f91899148dcd5654ef0a27676a654a...2d0980caad2814c8be776b496801f68c9a6c67e8
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/b56e0cd300f91899148dcd5654ef0a27676a654a...2d0980caad2814c8be776b496801f68c9a6c67e8
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/20230914/739bfe55/attachment-0001.html>
More information about the ghc-commits
mailing list