Improve inlining for local functions
See also
* #19643
* #3755
* #20516
* #21938
* #22317
* !8778 Andreas's MR addressing this issue
* [Problem with the binary library](https://gitlab.haskell.org/ghc/ghc/-/issues/21457#note_445884), and [the binary-library ticket](https://github.com/kolmodin/binary/issues/200)
I found that `boyer2/Rewritefuns.onewayunify1` has a join point that really should be inlined. It should get a big discount from scrutinizing free variables. But the inlining mechanism only take account of arguments, not free variables. There's a small optimisation opportunity here, which this ticket records.
See also: #4960
Here's the code:
```
Rewritefns.onewayunify1 =
\ (t1_acm :: Lisplikefns.Lisplist)
(t2_acn :: Lisplikefns.Lisplist)
(u_aco :: Lisplikefns.Lisplist) ->
case t2_acn of wild_ao1 {
__DEFAULT ->
case t1_acm of wild_Xok {
__DEFAULT ->
let {
$j_spS
:: GHC.Prim.State# GHC.Prim.RealWorld
-> (GHC.Bool.Bool, Lisplikefns.Lisplist)
[LclId,
Arity=1,
Unf=Unf{Src=<vanilla>, TopLvl=False, Arity=1, Value=True,
ConLike=True, Cheap=True, Expandable=True,
Guidance=IF_ARGS [0] 10 0}]
$j_spS =
\ _ ->
Rewritefns.onewayunify1lst
(case wild_Xok of _ {
Lisplikefns.Nil -> Lisplikefns.Nil;
Lisplikefns.Cons ds1_anT ->
case ds1_anT of _ { (_, y_anY) -> y_anY }
})
(case wild_ao1 of _ {
Lisplikefns.Nil -> Lisplikefns.Nil;
Lisplikefns.Cons ds1_anT ->
case ds1_anT of _ { (_, y_anY) -> y_anY }
})
u_aco } in
case wild_Xok of _ {
Lisplikefns.Nil ->
case wild_ao1 of _ {
Lisplikefns.Nil ->
case Lisplikefns.$fEqLisplist_$c== Lisplikefns.Nil Lisplikefns.Nil
of _ {
GHC.Bool.False -> (GHC.Bool.False, u_aco);
GHC.Bool.True -> $j_spS GHC.Prim.realWorld#
};
Lisplikefns.Cons ds1_anJ ->
case ds1_anJ of _ { (x_anN, _) ->
case Lisplikefns.$fEqLisplist_$c== Lisplikefns.Nil x_anN of _ {
GHC.Bool.False -> (GHC.Bool.False, u_aco);
GHC.Bool.True -> $j_spS GHC.Prim.realWorld#
}
}
};
Lisplikefns.Cons ds1_anJ ->
case ds1_anJ of _ { (x_anN, _) ->
case wild_ao1 of _ {
Lisplikefns.Nil ->
case Lisplikefns.$fEqLisplist_$c== x_anN Lisplikefns.Nil of _ {
GHC.Bool.False -> (GHC.Bool.False, u_aco);
GHC.Bool.True -> $j_spS GHC.Prim.realWorld#
};
Lisplikefns.Cons ds1_Xof ->
case ds1_Xof of _ { (x_Xom, _) ->
case Lisplikefns.$fEqLisplist_$c== x_anN x_Xom of _ {
GHC.Bool.False -> (GHC.Bool.False, u_aco);
GHC.Bool.True -> $j_spS GHC.Prim.realWorld#
}
}
}
}
};
Lisplikefns.Atom x_ao3 -> (GHC.Bool.False, u_aco)
};
```
You can see that `$j_sps` scrutinises `wild_Xok` and `wild_ao1`, but it currently gets no discount for doing so.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 6.12.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Improve inlining for local functions","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.12.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"I found that `boyer2/Rewritefuns.onewayunify1` has a join point that really should be inlined. It should get a big discount from scrutinizing free variables. But the inlining mechanism only take account of arguments, not free variables. There's a small optimisation opportunity here, which this ticket records. \r\n\r\nHere's the code:\r\n{{{\r\nRewritefns.onewayunify1 =\r\n \\ (t1_acm :: Lisplikefns.Lisplist)\r\n (t2_acn :: Lisplikefns.Lisplist)\r\n (u_aco :: Lisplikefns.Lisplist) ->\r\n case t2_acn of wild_ao1 {\r\n __DEFAULT ->\r\n case t1_acm of wild_Xok {\r\n __DEFAULT ->\r\n let {\r\n $j_spS\r\n :: GHC.Prim.State# GHC.Prim.RealWorld\r\n -> (GHC.Bool.Bool, Lisplikefns.Lisplist)\r\n [LclId,\r\n Arity=1,\r\n Unf=Unf{Src=<vanilla>, TopLvl=False, Arity=1, Value=True,\r\n ConLike=True, Cheap=True, Expandable=True,\r\n Guidance=IF_ARGS [0] 10 0}]\r\n $j_spS =\r\n \\ _ ->\r\n Rewritefns.onewayunify1lst\r\n (case wild_Xok of _ {\r\n Lisplikefns.Nil -> Lisplikefns.Nil;\r\n Lisplikefns.Cons ds1_anT ->\r\n case ds1_anT of _ { (_, y_anY) -> y_anY }\r\n })\r\n (case wild_ao1 of _ {\r\n Lisplikefns.Nil -> Lisplikefns.Nil;\r\n Lisplikefns.Cons ds1_anT ->\r\n case ds1_anT of _ { (_, y_anY) -> y_anY }\r\n })\r\n u_aco } in\r\n case wild_Xok of _ {\r\n Lisplikefns.Nil ->\r\n case wild_ao1 of _ {\r\n Lisplikefns.Nil ->\r\n case Lisplikefns.$fEqLisplist_$c== Lisplikefns.Nil Lisplikefns.Nil\r\n of _ {\r\n GHC.Bool.False -> (GHC.Bool.False, u_aco);\r\n GHC.Bool.True -> $j_spS GHC.Prim.realWorld#\r\n };\r\n Lisplikefns.Cons ds1_anJ ->\r\n case ds1_anJ of _ { (x_anN, _) ->\r\n case Lisplikefns.$fEqLisplist_$c== Lisplikefns.Nil x_anN of _ {\r\n GHC.Bool.False -> (GHC.Bool.False, u_aco);\r\n GHC.Bool.True -> $j_spS GHC.Prim.realWorld#\r\n }\r\n }\r\n };\r\n Lisplikefns.Cons ds1_anJ ->\r\n case ds1_anJ of _ { (x_anN, _) ->\r\n case wild_ao1 of _ {\r\n Lisplikefns.Nil ->\r\n case Lisplikefns.$fEqLisplist_$c== x_anN Lisplikefns.Nil of _ {\r\n GHC.Bool.False -> (GHC.Bool.False, u_aco);\r\n GHC.Bool.True -> $j_spS GHC.Prim.realWorld#\r\n };\r\n Lisplikefns.Cons ds1_Xof ->\r\n case ds1_Xof of _ { (x_Xom, _) ->\r\n case Lisplikefns.$fEqLisplist_$c== x_anN x_Xom of _ {\r\n GHC.Bool.False -> (GHC.Bool.False, u_aco);\r\n GHC.Bool.True -> $j_spS GHC.Prim.realWorld#\r\n }\r\n }\r\n }\r\n }\r\n };\r\n Lisplikefns.Atom x_ao3 -> (GHC.Bool.False, u_aco)\r\n };\r\n}}}\r\nYou can see that `$j_sps` scrutinises `wild_Xok` and `wild_ao1`, but it currently gets no discount for doing so.\r\n","type_of_failure":"OtherFailure","blocking":[]} -->
issue