GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2022-06-12T21:52:50Zhttps://gitlab.haskell.org/ghc/ghc/-/issues/1965Allow unconstrained existential contexts in newtypes2022-06-12T21:52:50ZguestAllow unconstrained existential contexts in newtypesDeclarations like
```
newtype Bar = forall a. Bar (Foo a)
```
ought to be allowed so long as no typeclass constraints are added. Right now, this requires data rather than newtype.
The wiki page [wiki:NewtypeOptimizationForGADTS](wiki:...Declarations like
```
newtype Bar = forall a. Bar (Foo a)
```
ought to be allowed so long as no typeclass constraints are added. Right now, this requires data rather than newtype.
The wiki page [wiki:NewtypeOptimizationForGADTS](wiki:NewtypeOptimizationForGADTS) summarises the proposal8.0.1https://gitlab.haskell.org/ghc/ghc/-/issues/2028STM slightly conservative on write-only transactions2019-07-07T19:10:32ZJulesBeanSTM slightly conservative on write-only transactionsThe STM appears to be slightly too conservative on write-only transactions.
It will store a copy of the current (that is, old) value on a writeTVar, even if it was never read from. This can cause a spurious retry.
E.g. `atomically $ wr...The STM appears to be slightly too conservative on write-only transactions.
It will store a copy of the current (that is, old) value on a writeTVar, even if it was never read from. This can cause a spurious retry.
E.g. `atomically $ writeTVar tv 0` really has no reason to ever retry. Neither, in fact, does `atomically $ mapM (\tv -> writeTVar tv 0) [tv1,tv2,tv3,tv4]`.
My suggestion is to instead indicate "no prior value" for that TVar, and then make no consistency checks on TVars marked as no prior value...
Jules
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 6.8.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | Unknown |
| Architecture | Unknown |
</details>
<!-- {"blocked_by":[],"summary":"STM slightly conservative on write-only transactions","status":"New","operating_system":"Unknown","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.8.1","keywords":[],"differentials":[],"test_case":"","architecture":"Unknown","cc":[""],"type":"Bug","description":"The STM appears to be slightly too conservative on write-only transactions.\r\n\r\nIt will store a copy of the current (that is, old) value on a writeTVar, even if it was never read from. This can cause a spurious retry.\r\n\r\nE.g. {{{atomically $ writeTVar tv 0}}} really has no reason to ever retry. Neither, in fact, does {{{atomically $ mapM (\\tv -> writeTVar tv 0) [tv1,tv2,tv3,tv4]}}}.\r\n\r\nMy suggestion is to instead indicate \"no prior value\" for that TVar, and then make no consistency checks on TVars marked as no prior value...\r\n\r\nJules\r\n\r\n","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1https://gitlab.haskell.org/ghc/ghc/-/issues/2041Allow splicing in concrete syntax2019-07-07T19:10:29ZIan Lynagh <igloo@earth.li>Allow splicing in concrete syntaxTemplate Haskell tends to lag behind GHC extensions, so it might be nice to allow concrete syntax to be returned, e.g. something like
```
f = $( return (RawE "5 + 6") )
```
There wouldn't be any need to restrict it to the top level, e....Template Haskell tends to lag behind GHC extensions, so it might be nice to allow concrete syntax to be returned, e.g. something like
```
f = $( return (RawE "5 + 6") )
```
There wouldn't be any need to restrict it to the top level, e.g. this would also be allowed:
```
f = $( return (InfixE (IntE 5) '(+) (RawE "6")) )
```
One possible disadvantage is that it might result in TH languishing even further behind, as there is less incentive to fill in the gaps.
Also, if a module splices in a raw expression from a TH library, what extensions should be enabled when parsing the string? Should we use the extensions enabled for the module, or should the `RawE` constructor specify the extensions to be used? We actually have this problem already, as (for example) when instances are spliced in we might need !OverlappingInstances enabled, so just using the extensions enabled for the module would be consistent.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ---------------- |
| Version | 6.8.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Template Haskell |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | Unknown |
| Architecture | Unknown |
</details>
<!-- {"blocked_by":[],"summary":"Allow splicing in concrete syntax","status":"New","operating_system":"Unknown","component":"Template Haskell","related":[],"milestone":"6.10 branch","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.8.2","keywords":[],"differentials":[],"test_case":"","architecture":"Unknown","cc":[""],"type":"Bug","description":"\r\nTemplate Haskell tends to lag behind GHC extensions, so it might be nice to allow concrete syntax to be returned, e.g. something like\r\n{{{\r\nf = $( return (RawE \"5 + 6\") )\r\n}}}\r\nThere wouldn't be any need to restrict it to the top level, e.g. this would also be allowed:\r\n{{{\r\nf = $( return (InfixE (IntE 5) '(+) (RawE \"6\")) )\r\n}}}\r\n\r\nOne possible disadvantage is that it might result in TH languishing even further behind, as there is less incentive to fill in the gaps.\r\n\r\nAlso, if a module splices in a raw expression from a TH library, what extensions should be enabled when parsing the string? Should we use the extensions enabled for the module, or should the `RawE` constructor specify the extensions to be used? We actually have this problem already, as (for example) when instances are spliced in we might need !OverlappingInstances enabled, so just using the extensions enabled for the module would be consistent.\r\n","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/2057inconsistent .hi file error gets ignored2019-07-07T19:10:24Zduncaninconsistent .hi file error gets ignored```
[20 of 20] Compiling Main ( ./Main.hs, dist/build/cabal/cabal-tmp/Main.o )
The interface for `main:Hackage.Config'
Declaration for savedConfigToConfigFlags
Unfolding of Hackage.Config.savedConfigToConfigFlags:
Can't fin...```
[20 of 20] Compiling Main ( ./Main.hs, dist/build/cabal/cabal-tmp/Main.o )
The interface for `main:Hackage.Config'
Declaration for savedConfigToConfigFlags
Unfolding of Hackage.Config.savedConfigToConfigFlags:
Can't find interface-file declaration for variable Distribution.Simple.Setup.a401
Probable cause: bug in .hi-boot file, or inconsistent .hi file
Use -ddump-if-trace to get an idea of which file caused the error
Linking dist/build/cabal/cabal ...
dist/build/cabal/cabal-tmp/Hackage/Config.o: In function `sfsu_info':
(.text+0x70cc): undefined reference to `Cabalzm1zi3zi3_DistributionziSimpleziSetup_a401_closure'
dist/build/cabal/cabal-tmp/Hackage/Config.o: In function `rf7U_closure':
(.data+0xf28): undefined reference to `Cabalzm1zi3zi3_DistributionziSimpleziSetup_a401_closure'
collect2: ld returned 1 exit status
```
Now, the inconsistent .hi file was entirely my fault. However note that `ghc --make` did not stop at the error! It continued and tried to link.
This is bad because sometimes linker errors are very long and a user might loose the real source of the error.
The error gets raised in `iface/TcIface.lhs` by `importDecl`. The uses of that function look like they are translating the error into failure in other monads ok. It's not immediately obvious at what point in the propagation of this error it gets ignored and linking continues irrespective.
It should not be too hard to reproduce I hope. Generating inconsistent .hi files is fairly easy to do. In this case I just built cabal-install against an existing Cabal. Then rebuilt and re-registered a slightly changed Cabal lib. Then did another build of cabal-install without cleaning first.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 6.8.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | Unknown |
| Architecture | Unknown |
</details>
<!-- {"blocked_by":[],"summary":"inconsistent .hi file error gets ignored","status":"New","operating_system":"Unknown","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.8.2","keywords":[],"differentials":[],"test_case":"","architecture":"Unknown","cc":[""],"type":"Bug","description":"{{{\r\n[20 of 20] Compiling Main ( ./Main.hs, dist/build/cabal/cabal-tmp/Main.o )\r\nThe interface for `main:Hackage.Config'\r\nDeclaration for savedConfigToConfigFlags\r\nUnfolding of Hackage.Config.savedConfigToConfigFlags:\r\n Can't find interface-file declaration for variable Distribution.Simple.Setup.a401\r\n Probable cause: bug in .hi-boot file, or inconsistent .hi file\r\n Use -ddump-if-trace to get an idea of which file caused the error\r\nLinking dist/build/cabal/cabal ...\r\ndist/build/cabal/cabal-tmp/Hackage/Config.o: In function `sfsu_info':\r\n(.text+0x70cc): undefined reference to `Cabalzm1zi3zi3_DistributionziSimpleziSetup_a401_closure'\r\ndist/build/cabal/cabal-tmp/Hackage/Config.o: In function `rf7U_closure':\r\n(.data+0xf28): undefined reference to `Cabalzm1zi3zi3_DistributionziSimpleziSetup_a401_closure'\r\ncollect2: ld returned 1 exit status\r\n}}}\r\n\r\nNow, the inconsistent .hi file was entirely my fault. However note that `ghc --make` did not stop at the error! It continued and tried to link.\r\n\r\nThis is bad because sometimes linker errors are very long and a user might loose the real source of the error.\r\n\r\nThe error gets raised in `iface/TcIface.lhs` by `importDecl`. The uses of that function look like they are translating the error into failure in other monads ok. It's not immediately obvious at what point in the propagation of this error it gets ignored and linking continues irrespective.\r\n\r\nIt should not be too hard to reproduce I hope. Generating inconsistent .hi files is fairly easy to do. In this case I just built cabal-install against an existing Cabal. Then rebuilt and re-registered a slightly changed Cabal lib. Then did another build of cabal-install without cleaning first.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/2075hpc should render information about the run in its html markup2019-07-07T19:10:19Zdonshpc should render information about the run in its html markupTo check if a generated coverage test is up to date, it would be useful to have hpc annotate its generated output with the date of the run, the compiler version, and OS info. Perhaps also information about which packages were included in...To check if a generated coverage test is up to date, it would be useful to have hpc annotate its generated output with the date of the run, the compiler version, and OS info. Perhaps also information about which packages were included in the build.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 6.8.2 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Code Coverage |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | Multiple |
| Architecture | Unknown |
</details>
<!-- {"blocked_by":[],"summary":"hpc should render information about the run in its html markup","status":"New","operating_system":"Multiple","component":"Code Coverage","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"OwnedBy","contents":"andy@galois.com"},"version":"6.8.2","keywords":[],"differentials":[],"test_case":"","architecture":"Unknown","cc":[""],"type":"FeatureRequest","description":"To check if a generated coverage test is up to date, it would be useful to have hpc annotate its generated output with the date of the run, the compiler version, and OS info. Perhaps also information about which packages were included in the build.","type_of_failure":"OtherFailure","blocking":[]} -->andy@galois.comandy@galois.comhttps://gitlab.haskell.org/ghc/ghc/-/issues/2076rational infinities don't compare correctly to each other2019-07-07T19:10:19Zuhollerbachrational infinities don't compare correctly to each otherLet pinf = 1%0, and ninf = (-1)%0; then (min ninf pinf) is correctly reported as (-1)%0, but (min pinf ninf) is reported as 1%0. Similar problems exist with max, (\<), (\>), (\<=), and (\>=). The (hopefully attached) test program shows t...Let pinf = 1%0, and ninf = (-1)%0; then (min ninf pinf) is correctly reported as (-1)%0, but (min pinf ninf) is reported as 1%0. Similar problems exist with max, (\<), (\>), (\<=), and (\>=). The (hopefully attached) test program shows the trouble. I have checked this on both 32-bit x86 and 64-bit amd64, both with ghc 6.8.2, both linux; both show the same trouble.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 6.8.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | Unknown |
| Architecture | Multiple |
</details>
<!-- {"blocked_by":[],"summary":"rational infinities don't compare correctly to each other","status":"New","operating_system":"Unknown","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.8.2","keywords":[],"differentials":[],"test_case":"","architecture":"Multiple","cc":[""],"type":"Bug","description":"Let pinf = 1%0, and ninf = (-1)%0; then (min ninf pinf) is correctly reported as (-1)%0, but (min pinf ninf) is reported as 1%0. Similar problems exist with max, (<), (>), (<=), and (>=). The (hopefully attached) test program shows the trouble. I have checked this on both 32-bit x86 and 64-bit amd64, both with ghc 6.8.2, both linux; both show the same trouble.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/2101Allow some form of type-level lemma2019-07-07T19:10:12ZguestAllow some form of type-level lemmaSee http://www.haskell.org/pipermail/haskell/2008-February/020230.html
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------------- |
| Version ...See http://www.haskell.org/pipermail/haskell/2008-February/020230.html
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------------- |
| Version | 6.8.2 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | ryani.spam@gmail.com |
| Operating system | Unknown |
| Architecture | Unknown |
</details>
<!-- {"blocked_by":[],"summary":"Allow some form of type-level lemma","status":"New","operating_system":"Unknown","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.8.2","keywords":[],"differentials":[],"test_case":"","architecture":"Unknown","cc":["ryani.spam@gmail.com"],"type":"FeatureRequest","description":"See http://www.haskell.org/pipermail/haskell/2008-February/020230.html","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/2119explicitly importing deprecated symbols should elicit the deprecation warning2022-07-12T19:17:27Zduncanexplicitly importing deprecated symbols should elicit the deprecation warningIf we explicitly import but do not use a deprecated function then ghc does not give the deprecation warning.
```
module Foo where
{-# DEPRECATED foo "don't use foo please, use ..." #-}
foo = ...
```
```
module Bar where
import Foo (foo...If we explicitly import but do not use a deprecated function then ghc does not give the deprecation warning.
```
module Foo where
{-# DEPRECATED foo "don't use foo please, use ..." #-}
foo = ...
```
```
module Bar where
import Foo (foo)
```
This is a bit annoying since it means client packages do not get any notification that some function is going to disappear but they would break if it does disappear. Or to look at it another way, it prevents me removing old deprecated functions because I don't want to break client programs but I have no way of communicating that to the author of a program that is importing but is no longer using the deprecated function.
My real world example is the Cabal lib and lhs2tex's Setup.hs file. It is importing `Distribution.Simple.LocalBuildInfo.mkDataDir` (which is deprecated in the current released Cabal version) but the Setup.hs is not actually using it, so the author got no indication that it should not be imported anymore. In the development version of Cabal I'd already removed this deprecated function since I assumed we'd given everyone plenty of warning. I'll have to go add `mkDataDir` back.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 6.8.2 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | Unknown |
| Architecture | Unknown |
</details>
<!-- {"blocked_by":[],"summary":"explicitly importing deprecated symbols should elicit the deprecation warning","status":"New","operating_system":"Unknown","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.8.2","keywords":[],"differentials":[],"test_case":"","architecture":"Unknown","cc":[""],"type":"FeatureRequest","description":"If we explicitly import but do not use a deprecated function then ghc does not give the deprecation warning.\r\n\r\n{{{\r\nmodule Foo where\r\n{-# DEPRECATED foo \"don't use foo please, use ...\" #-}\r\nfoo = ...\r\n}}}\r\n\r\n{{{\r\nmodule Bar where\r\nimport Foo (foo)\r\n}}}\r\n\r\nThis is a bit annoying since it means client packages do not get any notification that some function is going to disappear but they would break if it does disappear. Or to look at it another way, it prevents me removing old deprecated functions because I don't want to break client programs but I have no way of communicating that to the author of a program that is importing but is no longer using the deprecated function.\r\n\r\nMy real world example is the Cabal lib and lhs2tex's Setup.hs file. It is importing `Distribution.Simple.LocalBuildInfo.mkDataDir` (which is deprecated in the current released Cabal version) but the Setup.hs is not actually using it, so the author got no indication that it should not be imported anymore. In the development version of Cabal I'd already removed this deprecated function since I assumed we'd given everyone plenty of warning. I'll have to go add `mkDataDir` back.","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1https://gitlab.haskell.org/ghc/ghc/-/issues/2123implement waitForProcess using signals2019-07-07T19:10:06ZSimon Marlowimplement waitForProcess using signals`waitForProcess` currently calls `waitpid` with a safe FFI call, which means that
- you need to use `-threaded` to call this in a multithreaded program
- one OS thread is needed per `waitProcess`
instead we could implement this using t...`waitForProcess` currently calls `waitpid` with a safe FFI call, which means that
- you need to use `-threaded` to call this in a multithreaded program
- one OS thread is needed per `waitProcess`
instead we could implement this using the IO manager: have `waitForProcess` communicate with the IO manager, which wakes up the client when the appropriate `SIGCHLD` is received. Note that this means hooking `SIGCHLD` so we'd interact badly if the program itself wanted to use `SIGCHLD`.
I think it was Duncan Coutts who mentioned this idea to me.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ----------------- |
| Version | 6.8.2 |
| Type | Task |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/process |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | Unknown |
| Architecture | Unknown |
</details>
<!-- {"blocked_by":[],"summary":"implement waitForProcess using signals","status":"New","operating_system":"Unknown","component":"libraries/process","related":[],"milestone":"6.10 branch","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.8.2","keywords":[],"differentials":[],"test_case":"","architecture":"Unknown","cc":[""],"type":"Task","description":"`waitForProcess` currently calls `waitpid` with a safe FFI call, which means that \r\n\r\n * you need to use `-threaded` to call this in a multithreaded program\r\n * one OS thread is needed per `waitProcess`\r\n\r\ninstead we could implement this using the IO manager: have `waitForProcess` communicate with the IO manager, which wakes up the client when the appropriate `SIGCHLD` is received. Note that this means hooking `SIGCHLD` so we'd interact badly if the program itself wanted to use `SIGCHLD`.\r\n\r\nI think it was Duncan Coutts who mentioned this idea to me.","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1Michael Snoymanmichael@snoyman.comMichael Snoymanmichael@snoyman.comhttps://gitlab.haskell.org/ghc/ghc/-/issues/2132Optimise nested comparisons2022-03-07T07:16:18ZSimon Peyton JonesOptimise nested comparisonsGHC isn't capable of this optimisation:
```
case (x ># y) of ==> case (x ># y) of
True -> ...(x ==# y)... True -> ...False...
False -> ... False -> ...
```
That is, knowin...GHC isn't capable of this optimisation:
```
case (x ># y) of ==> case (x ># y) of
True -> ...(x ==# y)... True -> ...False...
False -> ... False -> ...
```
That is, knowing that (x\>y) we know that the two are not equal.
Also, consider this:
```
case (x ># y) of ==> case (x >=# y) of
True -> e True -> e
False -> case (x ==# y) of False -> e'
True -> e
False -> e'
```
Again this needs special knowlege about comparison operators. However, it *does* arise. Consider this:
```
data T = MkT Int deriving( Eq, Ord )
```
The derived `(>)` operation looks like this:
```
Foo.$dm> =
\ (eta_a8q :: Foo.T) (eta1_a8r :: Foo.T) ->
case eta_a8q of wild_B1 { Foo.MkT a1_a60 ->
case eta1_a8r of wild1_XO { Foo.MkT b1_a62 ->
case a1_a60 of wild2_a9I { GHC.Base.I# x#_a9K ->
case b1_a62 of wild11_a9M { GHC.Base.I# y#_a9O ->
case GHC.Prim.<# x#_a9K y#_a9O of wild3_a9W {
GHC.Base.False ->
case GHC.Prim.==# x#_a9K y#_a9O of wild12_a9Z {
GHC.Base.False -> GHC.Base.True; GHC.Base.True -> GHC.Base.False
};
GHC.Base.True -> GHC.Base.False
```
See also #2130
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 6.8.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | Unknown |
| Architecture | Unknown |
</details>
<!-- {"blocked_by":[],"summary":"Optimise nested comparisons","status":"New","operating_system":"Unknown","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.8.2","keywords":[],"differentials":[],"test_case":"","architecture":"Unknown","cc":[""],"type":"Bug","description":"GHC isn't capable of this optimisation:\r\n{{{\r\n case (x ># y) of ==> case (x ># y) of\r\n True -> ...(x ==# y)... True -> ...False...\r\n False -> ... False -> ...\r\n}}}\r\nThat is, knowing that (x>y) we know that the two are not equal.\r\n\r\nAlso, consider this:\r\n{{{\r\n case (x ># y) of ==> case (x >=# y) of\r\n True -> e True -> e\r\n False -> case (x ==# y) of False -> e'\r\n True -> e\r\n False -> e'\r\n}}}\r\nAgain this needs special knowlege about comparison operators. However, it ''does'' arise. Consider this:\r\n{{{\r\n data T = MkT Int deriving( Eq, Ord )\r\n}}}\r\nThe derived `(>)` operation looks like this:\r\n{{{\r\nFoo.$dm> =\r\n \\ (eta_a8q :: Foo.T) (eta1_a8r :: Foo.T) ->\r\n case eta_a8q of wild_B1 { Foo.MkT a1_a60 ->\r\n case eta1_a8r of wild1_XO { Foo.MkT b1_a62 ->\r\n case a1_a60 of wild2_a9I { GHC.Base.I# x#_a9K ->\r\n case b1_a62 of wild11_a9M { GHC.Base.I# y#_a9O ->\r\n case GHC.Prim.<# x#_a9K y#_a9O of wild3_a9W {\r\n GHC.Base.False ->\r\n case GHC.Prim.==# x#_a9K y#_a9O of wild12_a9Z {\r\n GHC.Base.False -> GHC.Base.True; GHC.Base.True -> GHC.Base.False\r\n };\r\n GHC.Base.True -> GHC.Base.False\r\n}}}\r\nSee also #2130","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/2135Warn if functions are exported whose types cannot be written2019-07-07T19:10:02ZdonsWarn if functions are exported whose types cannot be writtenIt should be possible to warn if a function is exported from a module whose type is hidden, and thus the function's type can't be written down directly by the user.
With the proliferation in type level programming in Haskell (and its us...It should be possible to warn if a function is exported from a module whose type is hidden, and thus the function's type can't be written down directly by the user.
With the proliferation in type level programming in Haskell (and its use in libraries), situations
can arise where functions are exported from a module which can be used, but whose type cannote be written, but where the type is complex enough that it really is required to write it down for the code to compile. This happened recently in the takusen library.
A warning for this situation would help authors of libraries avoid this situation.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | --------------- |
| Version | 6.8.2 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | dons@galois.com |
| Operating system | Unknown |
| Architecture | Unknown |
</details>
<!-- {"blocked_by":[],"summary":"Warn if functions are exported whose types cannot be written","status":"New","operating_system":"Unknown","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.8.2","keywords":["warnings"],"differentials":[],"test_case":"","architecture":"Unknown","cc":["dons@galois.com"],"type":"FeatureRequest","description":"It should be possible to warn if a function is exported from a module whose type is hidden, and thus the function's type can't be written down directly by the user.\r\n\r\nWith the proliferation in type level programming in Haskell (and its use in libraries), situations\r\ncan arise where functions are exported from a module which can be used, but whose type cannote be written, but where the type is complex enough that it really is required to write it down for the code to compile. This happened recently in the takusen library.\r\n\r\nA warning for this situation would help authors of libraries avoid this situation.\r\n\r\n","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1https://gitlab.haskell.org/ghc/ghc/-/issues/2140cpuTimePrecision is wrong2019-07-07T19:10:01ZguestcpuTimePrecision is wrong(From Adrian Hey)
Looking at the source code, this seems to be fixed
at 1000000000 independent of hardware. I'm not sure
if this is supposed to be the same on all Windows XP systems, but it's wrong on my machine at least.
getCPUTime al...(From Adrian Hey)
Looking at the source code, this seems to be fixed
at 1000000000 independent of hardware. I'm not sure
if this is supposed to be the same on all Windows XP systems, but it's wrong on my machine at least.
getCPUTime always returns a multiple of 15625000000
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 6.8.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/base |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | Windows |
| Architecture | x86_64 (amd64) |
</details>
<!-- {"blocked_by":[],"summary":"cpuTimePrecision is wrong for me on Windows (XP)","status":"New","operating_system":"Windows","component":"libraries/base","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.8.2","keywords":[],"differentials":[],"test_case":"","architecture":"x86_64 (amd64)","cc":[""],"type":"Bug","description":"(From Adrian Hey)\r\n\r\nLooking at the source code, this seems to be fixed\r\nat 1000000000 independent of hardware. I'm not sure\r\nif this is supposed to be the same on all Windows XP systems, but it's wrong on my machine at least.\r\n\r\ngetCPUTime always returns a multiple of 15625000000","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1Edward KmettEdward Kmetthttps://gitlab.haskell.org/ghc/ghc/-/issues/2147unhelpful error message for a misplaced DEPRECATED pragma2022-03-07T07:17:36Zguestunhelpful error message for a misplaced DEPRECATED pragmaThe error message on a misplaced DEPRECATED pragma is less than helpful. Note that it was the latter of these that bit me.
**% cat Main.hs**
```
module Main where
import Foo.Bar
main = return ()
```
**% cat Foo/Bar.hs**
```
{-# DEP...The error message on a misplaced DEPRECATED pragma is less than helpful. Note that it was the latter of these that bit me.
**% cat Main.hs**
```
module Main where
import Foo.Bar
main = return ()
```
**% cat Foo/Bar.hs**
```
{-# DEPRECATED foo "bar" #-}
module Foo.Bar (foo) where
foo = undefined
```
**% ghc -c Foo/Bar.hs**
> Foo/Bar.hs:4:0: parse error on input \`module'
**% ghc --make Main.hs**
> Foo/Bar.hs:1:0: file name does not match module name \`Main'8.0.1https://gitlab.haskell.org/ghc/ghc/-/issues/2180Any installed signal handler stops deadlock detection, but XCPU never happens...2019-07-07T19:09:50ZBaughnAny installed signal handler stops deadlock detection, but XCPU never happens in a deadlockThe runtime system's deadlock detection, being a debugging feature, rightly doesn't break a deadlock if there's any chance a signal will do so later. However, if the only installed signal is XCPU - cpu time-limit exceeded - then that wil...The runtime system's deadlock detection, being a debugging feature, rightly doesn't break a deadlock if there's any chance a signal will do so later. However, if the only installed signal is XCPU - cpu time-limit exceeded - then that will almost never happen in practice; any program that does want to wait for it will be waiting quite literally years.
As such, it seems best if XCPU is left out of the signal-detection logic. The attached patch does this.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ---------------- |
| Version | 6.9 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Runtime System |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | svein.ove@aas.no |
| Operating system | Multiple |
| Architecture | Unknown |
</details>
<!-- {"blocked_by":[],"summary":"Any installed signal handler stops deadlock detection, but XCPU never happens in a deadlock","status":"New","operating_system":"Multiple","component":"Runtime System","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"OwnedBy","contents":"Baughn"},"version":"6.9","keywords":[],"differentials":[],"test_case":"","architecture":"Unknown","cc":["svein.ove@aas.no"],"type":"FeatureRequest","description":"The runtime system's deadlock detection, being a debugging feature, rightly doesn't break a deadlock if there's any chance a signal will do so later. However, if the only installed signal is XCPU - cpu time-limit exceeded - then that will almost never happen in practice; any program that does want to wait for it will be waiting quite literally years.\r\n\r\nAs such, it seems best if XCPU is left out of the signal-detection logic. The attached patch does this.","type_of_failure":"OtherFailure","blocking":[]} -->BaughnBaughnhttps://gitlab.haskell.org/ghc/ghc/-/issues/2200big static random access arrays2020-05-23T14:31:05Zjsnxbig static random access arraysThese would be unlike `StorableArray`s because they would be available at compile time, and would be pure values. They would amount to arrays of bytes, of course, but it'd be nice if they could be `(Storable a) => StaticArray a` and we c...These would be unlike `StorableArray`s because they would be available at compile time, and would be pure values. They would amount to arrays of bytes, of course, but it'd be nice if they could be `(Storable a) => StaticArray a` and we could walk down them or randomly access them to get the `a` values out of them. They should be capable of storing hundreds of thousands of `Int`s.
What are some functions that work on these arrays? We need just one:
```
indexInto :: (Storable a) => StaticArray a -> Word -> a
```
Then we can make a `Monad` to walk up and down the array. It will be some `State` hybrid. No `IO`. A bright person could implement static `Trie`s, `RoseTree`s and other things using this `Monad` -- storing the offsets mixed in with the data in an unholy mess and skipping forward or backward, leveraging "the world’s most beautiful imperative language."
It's been suggested (SamB) that this should be implemented in Template Haskell.
Important features of this array relative to other arrays and lists in Haskell:
<table><tr><th>Specificity of Index</th>
<td>A machine `Word` since that contains the finest grained pointer. When indexing into a `Storable a`, the index is multiplied by `sizeOf (undefined :: a)`. </td></tr>
<tr><th>Static Nature</th>
<td>Exists to facilitate large static constants. The array does not support any append or delete operations, there is no way to change any of its values and it can not be copied.</td></tr></table>
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 6.8.2 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | SamB |
| Operating system | Multiple |
| Architecture | Multiple |
</details>
<!-- {"blocked_by":[],"summary":"big static random access arrays","status":"New","operating_system":"Multiple","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.8.2","keywords":["array","static"],"differentials":[],"test_case":"","architecture":"Multiple","cc":["SamB"],"type":"FeatureRequest","description":"\r\nThese would be unlike `StorableArray`s because they would be available at compile time, and would be pure values. They would amount to arrays of bytes, of course, but it'd be nice if they could be `(Storable a) => StaticArray a` and we could walk down them or randomly access them to get the `a` values out of them. They should be capable of storing hundreds of thousands of `Int`s.\r\n\r\nWhat are some functions that work on these arrays? We need just one:\r\n{{{\r\nindexInto :: (Storable a) => StaticArray a -> Word -> a\r\n}}}\r\n\r\nThen we can make a `Monad` to walk up and down the array. It will be some `State` hybrid. No `IO`. A bright person could implement static `Trie`s, `RoseTree`s and other things using this `Monad` -- storing the offsets mixed in with the data in an unholy mess and skipping forward or backward, leveraging \"the world’s most beautiful imperative language.\"\r\n\r\nIt's been suggested (SamB) that this should be implemented in Template Haskell.\r\n\r\nImportant features of this array relative to other arrays and lists in Haskell:\r\n\r\n Specificity of Index::\r\n A machine `Word` since that contains the finest grained pointer. When indexing into a `Storable a`, the index is multiplied by `sizeOf (undefined :: a)`. \r\n\r\n Static Nature::\r\n Exists to facilitate large static constants. The array does not support any append or delete operations, there is no way to change any of its values and it can not be copied.","type_of_failure":"OtherFailure","blocking":[]} -->Edward KmettEdward Kmetthttps://gitlab.haskell.org/ghc/ghc/-/issues/2207Load the interface details for GHC.* even without -O2023-12-08T21:30:56ZSimon Peyton JonesLoad the interface details for GHC.* even without -ONeil says: I just tried compiling the following program:
```
foo = (1 :: Int) == (2 :: Int)
```
with `ghc --ddump-simpl`, and no optimisation flags, in GHC 6.6.1
The resultant code is:
```
Test.foo =
case GHC.Base.$f2 of tpl_X8 { G...Neil says: I just tried compiling the following program:
```
foo = (1 :: Int) == (2 :: Int)
```
with `ghc --ddump-simpl`, and no optimisation flags, in GHC 6.6.1
The resultant code is:
```
Test.foo =
case GHC.Base.$f2 of tpl_X8 { GHC.Base.:DEq tpl1_B2 tpl2_B3 ->
tpl1_B2 (GHC.Base.I# 1) (GHC.Base.I# 2)
}
```
GHC has introduced dictionaries in this example. In comparison, Yhc
and nhc wouldn't introduce dictionaries here, as the type class
desugaring knows the type of the item is fixed, and makes a direct
call to the appropriate function.
If the desugaring was changed, it would make programs in GHCi run
faster, would reduce the size of programs, and would speed up the
optimiser, as it would have less to do. I am not sure how much
additional work this would require in the simplifier, but if it was
minimal, the gains would probably be worth it.
The reason nothing happens is that without -0 GHC does not load the unfoldings for anything from interface files, including `GHC.Base`. Idea: even without -O, load the unfoldings from GHC.\* modules. That would pick up a lot of very fundamental stuff, and might, as Neil says, make compilation faster.
Relatively easy to try. But would need a good nofib run to test the effects. Any takers? I'd point you at what to change.
Simon
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 6.8.2 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | Unknown |
| Architecture | Unknown |
</details>
<!-- {"blocked_by":[],"summary":"Load the interface details for GHC.* even without -O","status":"New","operating_system":"Unknown","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.8.2","keywords":[],"differentials":[],"test_case":"","architecture":"Unknown","cc":[""],"type":"FeatureRequest","description":"Neil says: I just tried compiling the following program:\r\n{{{\r\nfoo = (1 :: Int) == (2 :: Int)\r\n}}}\r\nwith `ghc --ddump-simpl`, and no optimisation flags, in GHC 6.6.1\r\n\r\nThe resultant code is:\r\n{{{\r\nTest.foo =\r\n case GHC.Base.$f2 of tpl_X8 { GHC.Base.:DEq tpl1_B2 tpl2_B3 ->\r\n tpl1_B2 (GHC.Base.I# 1) (GHC.Base.I# 2)\r\n }\r\n}}}\r\nGHC has introduced dictionaries in this example. In comparison, Yhc\r\nand nhc wouldn't introduce dictionaries here, as the type class\r\ndesugaring knows the type of the item is fixed, and makes a direct\r\ncall to the appropriate function.\r\n\r\nIf the desugaring was changed, it would make programs in GHCi run\r\nfaster, would reduce the size of programs, and would speed up the\r\noptimiser, as it would have less to do. I am not sure how much\r\nadditional work this would require in the simplifier, but if it was\r\nminimal, the gains would probably be worth it.\r\n\r\nThe reason nothing happens is that without -0 GHC does not load the unfoldings for anything from interface files, including `GHC.Base`. Idea: even without -O, load the unfoldings from GHC.* modules. That would pick up a lot of very fundamental stuff, and might, as Neil says, make compilation faster.\r\n\r\nRelatively easy to try. But would need a good nofib run to test the effects. Any takers? I'd point you at what to change.\r\n\r\nSimon","type_of_failure":"OtherFailure","blocking":[]} -->AzelAzelhttps://gitlab.haskell.org/ghc/ghc/-/issues/2224-fhpc inteferes/prevents rewrite rules from firing2019-07-07T19:09:39Zdons-fhpc inteferes/prevents rewrite rules from firingUse case:
I'm writing tests for rewrite rules, and using HPC to determine if rules were fired (and their code exercised). HPC is quite cool here, since it lets us see which rules fired, without needing to explicitly export functions to ...Use case:
I'm writing tests for rewrite rules, and using HPC to determine if rules were fired (and their code exercised). HPC is quite cool here, since it lets us see which rules fired, without needing to explicitly export functions to test.
However, -fhpc seems to prevent many rules from firing (likely due to ticks getting in the way?)
For example:
```
import qualified Data.ByteString.Char8 as C
main = print (C.pack "literal")
```
When compiled normally, triggers a nice rewrite rule:
```
$ ghc -O2 A.hs -ddump-rule-firings -c
Rule fired: unpack
Rule fired: Class op show
Rule fired: unpack-list
Rule fired: ByteString packChars/packAddress
```
Now with -fhpc:
```
$ ghc -O2 A.hs -ddump-rule-firings A.hs -c -fhpc
Rule fired: unpack
Rule fired: Class op show
Rule fired: unpack-list
```
What's the best way to ensure the same code is exercised with and without -fhpc here? (I'd quite like to get this working, since rewrite rules benefit from testing.)8.0.1andy@galois.comandy@galois.comhttps://gitlab.haskell.org/ghc/ghc/-/issues/2255Improve SpecConstr for free variables2019-07-07T19:09:28ZSimon Peyton JonesImprove SpecConstr for free variablesThis ticket records a suggestion for improving `SpecConstr`, so we don't lose it. The original `SpecConstr` transformation is described in "[Call pattern specialisation for Haskell](http://research.microsoft.com/%7Esimonpj/papers/spec-co...This ticket records a suggestion for improving `SpecConstr`, so we don't lose it. The original `SpecConstr` transformation is described in "[Call pattern specialisation for Haskell](http://research.microsoft.com/%7Esimonpj/papers/spec-constr)". Consider this program
```
f x = let g y = ...case x of { z:zs -> e1; [] -> e2 } ...
in
...case x of
z:zs -> if ... then g 3 else g 4
[] -> ...
```
Here 'x' is free in 'g', but x's value is known at g's call sites. It's not enough just to know "x is a cons" inside g; we must also have access to z,zs. So perhaps the thing to do is to imagine lambda-lifting 'g' to become 'gl' thus:
```
gl x y = ...case x of { z:zs -> e1; [] -> e2 } ...
f x = ...case x of
z:zs -> if ... then gl x 3 else gl x 4
[] -> ...
```
Now the `SpecConstr` transformation will apply nicely. And it's arguably a bad shortcoming that currently the mere act of lambda lifting can affect how effective `SpecConstr` is.
Of course, we only want to lambda-lift wrt the parameters that'll be specialised, so this transformation probably wants to be done at the same time as the rest of `SpecConstr`. I don't have much idea of how hard that'd be, but it's a nice idea.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 6.8.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | Unknown |
| Architecture | Unknown |
</details>
<!-- {"blocked_by":[],"summary":"Improve SpecConstr for free variables","status":"New","operating_system":"Unknown","component":"Compiler","related":[],"milestone":"⊥","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.8.2","keywords":[],"differentials":[],"test_case":"","architecture":"Unknown","cc":[""],"type":"Bug","description":"This ticket records a suggestion for improving `SpecConstr`, so we don't lose it. The original `SpecConstr` transformation is described in \"[http://research.microsoft.com/%7Esimonpj/papers/spec-constr Call pattern specialisation for Haskell]\". Consider this program\r\n{{{\r\n f x = let g y = ...case x of { z:zs -> e1; [] -> e2 } ...\r\n in\r\n ...case x of\r\n z:zs -> if ... then g 3 else g 4\r\n [] -> ...\r\n}}}\r\nHere 'x' is free in 'g', but x's value is known at g's call sites. It's not enough just to know \"x is a cons\" inside g; we must also have access to z,zs. So perhaps the thing to do is to imagine lambda-lifting 'g' to become 'gl' thus:\r\n{{{\r\n gl x y = ...case x of { z:zs -> e1; [] -> e2 } ...\r\n\r\n f x = ...case x of\r\n z:zs -> if ... then gl x 3 else gl x 4\r\n [] -> ...\r\n}}}\r\nNow the `SpecConstr` transformation will apply nicely. And it's arguably a bad shortcoming that currently the mere act of lambda lifting can affect how effective `SpecConstr` is.\r\n\r\nOf course, we only want to lambda-lift wrt the parameters that'll be specialised, so this transformation probably wants to be done at the same time as the rest of `SpecConstr`. I don't have much idea of how hard that'd be, but it's a nice idea.\r\n","type_of_failure":"OtherFailure","blocking":[]} -->⊥https://gitlab.haskell.org/ghc/ghc/-/issues/2258ghc --cleanup2022-04-11T22:24:33Zclaus.reinke@talk21.comghc --cleanupcalling `ghc --make` generates a lot of files, `.o`, `.hi`, `.exe`, `.exe.manifest`, .. moreover, those files may be in different directories, etc.
a nice way to get rid of all those leftovers would be a `ghc --cleanup`, with the same o...calling `ghc --make` generates a lot of files, `.o`, `.hi`, `.exe`, `.exe.manifest`, .. moreover, those files may be in different directories, etc.
a nice way to get rid of all those leftovers would be a `ghc --cleanup`, with the same options and parameters as `ghc --make`, which would delete everything that `ghc --make` would generate.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 6.8.2 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | Unknown |
| Architecture | Unknown |
</details>
<!-- {"blocked_by":[],"summary":"ghc --cleanup","status":"New","operating_system":"Unknown","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.8.2","keywords":[],"differentials":[],"test_case":"","architecture":"Unknown","cc":[""],"type":"FeatureRequest","description":"calling `ghc --make` generates a lot of files, `.o`, `.hi`, `.exe`, `.exe.manifest`, .. moreover, those files may be in different directories, etc.\r\n\r\na nice way to get rid of all those leftovers would be a `ghc --cleanup`, with the same options and parameters as `ghc --make`, which would delete everything that `ghc --make` would generate.","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1VictorDenisovVictorDenisovhttps://gitlab.haskell.org/ghc/ghc/-/issues/2289Needless reboxing of values when returning from a tight loop2021-10-05T08:00:20ZdonsNeedless reboxing of values when returning from a tight loopGHC wants to box up strict values when returning from tight inner loops, even when they're
immediately taken apart. This leads to redundant instructions in the bodies of tight loops,
and more code.
It affects, in particular, loops that ...GHC wants to box up strict values when returning from tight inner loops, even when they're
immediately taken apart. This leads to redundant instructions in the bodies of tight loops,
and more code.
It affects, in particular, loops that result from fusion, which need to be tight, but often return multiple values via unlifted pairs.
Consider this program:
```
{-# OPTIONS -fexcess-precision #-}
{-# LANGUAGE TypeOperators #-}
import System.Environment
import Text.Printf
import Data.Array.Vector
mean :: UArr Double -> Double
mean arr = s / fromIntegral l
where
s :*: l = foldlU k (0 :*: 0) arr :: (Double :*: Int)
k (s :*: n) x = s+x :*: n+1
main = do
[d] <- map read `fmap` getArgs
printf "%f\n" (mean (enumFromToFracU 1 d))
```
It generates this rather good Core (ghc 6.8.2):
```
$s$wfold_s1rB :: Double#
-> Int#
-> Double#
-> (# Double, Int #)
$s$wfold_s1rB =
\ (sc_s1rr :: Double#)
(sc1_s1rs :: Int#)
(sc2_s1rt :: Double#) ->
case >## sc_s1rr y_a1pr of wild4_X1no {
False ->
$s$wfold_s1rB
(+## sc_s1rr 1.0)
(+# sc1_s1rs 1)
(+## sc2_s1rt sc_s1rr);
True -> (# D# sc2_s1rt, I# sc1_s1rs #)
};
} in
case $s$wfold_s1rB 2.0 1 1.0 of ww_s1qg { (# ww1_s1qi, ww2_s1qj #) ->
case ww1_s1qi of wild4_a1mC { D# x_a1mE ->
case ww2_s1qj of wild5_aP6 { I# x1_aP8 ->
case /## x_a1mE (int2Double# x1_aP8)
of wild21_a1mK { __DEFAULT ->
D# wild21_a1mK
```
But note, what's this?
```
True -> (# D# sc2_s1rt, I# sc1_s1rs #)
};
} in
case $s$wfold_s1rB 2.0 1 1.0 of ww_s1qg { (# ww1_s1qi, ww2_s1qj #) ->
case ww1_s1qi of wild4_a1mC { D# x_a1mE ->
case ww2_s1qj of wild5_aP6 { I# x1_aP8 ->
case /## x_a1mE (int2Double# x1_aP8)
```
The return values of what was a strict pair are boxed, placed in an unboxed tuple,
and then immediately unboxed and the division takes place.
Ok, let's isolate this. Here, the boxed return, from the inner loop:
```
mean_s19V :: Double#
-> Int#
-> Double#
-> (# Double, Int #)
mean_s19V =
\ (ds1_dD3 :: Double#)
(ds2_dD4 :: Int#)
(ds3_dD5 :: Double#) ->
case >## ds1_dD3 d#_aoG of wild4_Xw {
False ->
mean_s19V
(+## ds1_dD3 1.0)
(+# ds2_dD4 1)
(+## ds3_dD5 ds1_dD3);
True -> (# D# ds3_dD5, I# ds2_dD4 #)
};
} in
case mean_s19V 2.0 1 1.0 of wild4_Xr { (# ds1_dCV, ds2_dCW #) ->
case ds1_dCV of wild5_Xv { D# x_aoR ->
case ds2_dCW of wild6_Xy { I# y_aoS ->
case /## x_aoR (int2Double# y_aoS) of wild7_XB { __DEFAULT ->
D# wild7_XB
```
And the inner loop and exit:
```
s1bd_info:
-- what's this stuff?
leaq 32(%r12), %rax
cmpq %r15, %rax
movq %rax, %r12
ja .L17
-- ok, to business:
ucomisd 5(%rbx), %xmm5
ja .L19
movapd %xmm6, %xmm0
leaq -32(%rax), %r12
incq %rsi
addsd %xmm5, %xmm0
addsd .LC1(%rip), %xmm5
movapd %xmm0, %xmm6
jmp s1bd_info
.L19:
movq %rsi, -16(%rax)
movq $base_GHCziBase_Izh_con_info, -24(%rax)
movq $base_GHCziFloat_Dzh_con_info, -8(%rax)
movsd %xmm6, (%rax)
leaq -7(%rax), %rbx
leaq -23(%rax), %rsi
jmp *(%rbp)
```
Now, I can avoid the reboxing manually:
```
mean_s19R :: Double#
-> Int#
-> Double#
-> (# Double#, Int# #)
mean_s19R =
\ (ds1_dCZ :: Double#)
(ds2_dD0 :: Int#)
(ds3_dD1 :: Double#) ->
case >## ds1_dCZ d#_aoG of wild4_Xw {
False ->
mean_s19R
(+## ds1_dCZ 1.0)
(+# ds2_dD0 1)
(+## ds3_dD1 ds1_dCZ);
True -> (# ds3_dD1, ds2_dD0 #)
};
} in
case mean_s19R 2.0 1 1.0 of wild4_Xr { (# x_aoR, y_aoS #) ->
case /## x_aoR (int2Double# y_aoS) of wild5_Xv { __DEFAULT ->
D# wild5_Xv
```
And we get:
```
s1b9_info:
-- hey , our junk is gone!
ucomisd 5(%rbx), %xmm5
ja .L17
movapd %xmm6, %xmm0
incq %rsi
addsd %xmm5, %xmm0
addsd .LC1(%rip), %xmm5
movapd %xmm0, %xmm6
jmp s1b9_info
-- cool, that was it, let's go home:
.L17:
movapd %xmm6, %xmm5
movq %rsi, %rbx
jmp *(%rbp)
```
Which is a much better result. The loop is tighter.
What can be done here?
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | --------------- |
| Version | 6.8.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | dons@galois.com |
| Operating system | Unknown |
| Architecture | Unknown |
</details>
<!-- {"blocked_by":[],"summary":"Needless reboxing of values when returning from a tight loop","status":"New","operating_system":"Unknown","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.8.2","keywords":["boxing,","loops,","performance"],"differentials":[],"test_case":"","architecture":"Unknown","cc":["dons@galois.com"],"type":"Bug","description":"GHC wants to box up strict values when returning from tight inner loops, even when they're\r\nimmediately taken apart. This leads to redundant instructions in the bodies of tight loops,\r\nand more code. \r\n\r\nIt affects, in particular, loops that result from fusion, which need to be tight, but often return multiple values via unlifted pairs.\r\n\r\nConsider this program:\r\n\r\n{{{\r\n{-# OPTIONS -fexcess-precision #-}\r\n{-# LANGUAGE TypeOperators #-}\r\n\r\nimport System.Environment\r\nimport Text.Printf\r\nimport Data.Array.Vector\r\n\r\nmean :: UArr Double -> Double\r\nmean arr = s / fromIntegral l\r\n where\r\n s :*: l = foldlU k (0 :*: 0) arr :: (Double :*: Int)\r\n k (s :*: n) x = s+x :*: n+1\r\n\r\nmain = do\r\n [d] <- map read `fmap` getArgs\r\n printf \"%f\\n\" (mean (enumFromToFracU 1 d))\r\n}}}\r\n\r\nIt generates this rather good Core (ghc 6.8.2):\r\n\r\n{{{\r\n$s$wfold_s1rB :: Double#\r\n -> Int#\r\n -> Double#\r\n -> (# Double, Int #)\r\n\r\n$s$wfold_s1rB =\r\n\\ (sc_s1rr :: Double#)\r\n (sc1_s1rs :: Int#)\r\n (sc2_s1rt :: Double#) ->\r\n case >## sc_s1rr y_a1pr of wild4_X1no {\r\n False ->\r\n $s$wfold_s1rB\r\n (+## sc_s1rr 1.0)\r\n (+# sc1_s1rs 1)\r\n (+## sc2_s1rt sc_s1rr);\r\n True -> (# D# sc2_s1rt, I# sc1_s1rs #)\r\n };\r\n} in \r\ncase $s$wfold_s1rB 2.0 1 1.0 of ww_s1qg { (# ww1_s1qi, ww2_s1qj #) ->\r\ncase ww1_s1qi of wild4_a1mC { D# x_a1mE ->\r\ncase ww2_s1qj of wild5_aP6 { I# x1_aP8 ->\r\ncase /## x_a1mE (int2Double# x1_aP8)\r\nof wild21_a1mK { __DEFAULT ->\r\nD# wild21_a1mK\r\n}}}\r\n\r\nBut note, what's this?\r\n\r\n{{{\r\n True -> (# D# sc2_s1rt, I# sc1_s1rs #)\r\n };\r\n} in \r\ncase $s$wfold_s1rB 2.0 1 1.0 of ww_s1qg { (# ww1_s1qi, ww2_s1qj #) ->\r\ncase ww1_s1qi of wild4_a1mC { D# x_a1mE ->\r\ncase ww2_s1qj of wild5_aP6 { I# x1_aP8 ->\r\ncase /## x_a1mE (int2Double# x1_aP8)\r\n\r\n}}}\r\n\r\nThe return values of what was a strict pair are boxed, placed in an unboxed tuple,\r\nand then immediately unboxed and the division takes place.\r\n\r\nOk, let's isolate this. Here, the boxed return, from the inner loop:\r\n\r\n{{{\r\nmean_s19V :: Double#\r\n -> Int#\r\n -> Double#\r\n -> (# Double, Int #)\r\n\r\nmean_s19V =\r\n\\ (ds1_dD3 :: Double#)\r\n (ds2_dD4 :: Int#)\r\n (ds3_dD5 :: Double#) ->\r\n case >## ds1_dD3 d#_aoG of wild4_Xw {\r\n False ->\r\n mean_s19V\r\n (+## ds1_dD3 1.0)\r\n (+# ds2_dD4 1)\r\n (+## ds3_dD5 ds1_dD3);\r\n True -> (# D# ds3_dD5, I# ds2_dD4 #)\r\n };\r\n} in \r\ncase mean_s19V 2.0 1 1.0 of wild4_Xr { (# ds1_dCV, ds2_dCW #) ->\r\ncase ds1_dCV of wild5_Xv { D# x_aoR ->\r\ncase ds2_dCW of wild6_Xy { I# y_aoS ->\r\ncase /## x_aoR (int2Double# y_aoS) of wild7_XB { __DEFAULT ->\r\nD# wild7_XB\r\n}}}\r\n\r\nAnd the inner loop and exit:\r\n\r\n{{{\r\ns1bd_info:\r\n\r\n -- what's this stuff?\r\n leaq 32(%r12), %rax\r\n cmpq %r15, %rax\r\n movq %rax, %r12\r\n ja .L17\r\n\r\n -- ok, to business:\r\n ucomisd 5(%rbx), %xmm5\r\n ja .L19\r\n movapd %xmm6, %xmm0\r\n leaq -32(%rax), %r12\r\n incq %rsi\r\n addsd %xmm5, %xmm0\r\n addsd .LC1(%rip), %xmm5\r\n movapd %xmm0, %xmm6\r\n jmp s1bd_info\r\n\r\n\r\n.L19:\r\n movq %rsi, -16(%rax)\r\n movq $base_GHCziBase_Izh_con_info, -24(%rax)\r\n movq $base_GHCziFloat_Dzh_con_info, -8(%rax)\r\n movsd %xmm6, (%rax)\r\n leaq -7(%rax), %rbx\r\n leaq -23(%rax), %rsi\r\n jmp *(%rbp)\r\n}}}\r\n\r\nNow, I can avoid the reboxing manually:\r\n\r\n{{{\r\nmean_s19R :: Double#\r\n -> Int#\r\n -> Double#\r\n -> (# Double#, Int# #)\r\n\r\nmean_s19R =\r\n\\ (ds1_dCZ :: Double#)\r\n (ds2_dD0 :: Int#)\r\n (ds3_dD1 :: Double#) ->\r\n case >## ds1_dCZ d#_aoG of wild4_Xw {\r\n False ->\r\n mean_s19R\r\n (+## ds1_dCZ 1.0)\r\n (+# ds2_dD0 1)\r\n (+## ds3_dD1 ds1_dCZ);\r\n True -> (# ds3_dD1, ds2_dD0 #)\r\n };\r\n} in \r\ncase mean_s19R 2.0 1 1.0 of wild4_Xr { (# x_aoR, y_aoS #) ->\r\ncase /## x_aoR (int2Double# y_aoS) of wild5_Xv { __DEFAULT ->\r\nD# wild5_Xv\r\n}}}\r\n\r\nAnd we get:\r\n\r\n{{{\r\ns1b9_info:\r\n -- hey , our junk is gone!\r\n\r\n ucomisd 5(%rbx), %xmm5\r\n ja .L17\r\n movapd %xmm6, %xmm0\r\n incq %rsi\r\n addsd %xmm5, %xmm0\r\n addsd .LC1(%rip), %xmm5\r\n movapd %xmm0, %xmm6\r\n jmp s1b9_info\r\n\r\n-- cool, that was it, let's go home:\r\n.L17:\r\n movapd %xmm6, %xmm5\r\n movq %rsi, %rbx\r\n jmp *(%rbp)\r\n\r\n}}}\r\n\r\nWhich is a much better result. The loop is tighter.\r\n\r\nWhat can be done here?","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1