GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2022-05-05T22:16:51Zhttps://gitlab.haskell.org/ghc/ghc/-/issues/13167GC and weak reference finalizers and exceptions2022-05-05T22:16:51ZYurasGC and weak reference finalizers and exceptionsWhen GC runs a number of finalizers in a row, and the first of them throws an exception, then other finalizers are ignored. The relevant piece of code is [here](https://github.com/ghc/ghc/blob/fb4092642f057f258d07cd6979925f4e2579eda6/lib...When GC runs a number of finalizers in a row, and the first of them throws an exception, then other finalizers are ignored. The relevant piece of code is [here](https://github.com/ghc/ghc/blob/fb4092642f057f258d07cd6979925f4e2579eda6/libraries/base/GHC/Weak.hs#L144).
The following program reproduces the issue:
```
import Data.IORef
import Control.Monad
import Control.Exception
import System.Mem
main :: IO ()
main = do
run
run
run
run
performMajorGC
performMajorGC
run :: IO ()
run = do
ref <- newIORef ()
void $ mkWeakIORef ref $ do
putStr "."
throwIO $ ErrorCall "failed"
```
I expect it to output "....", but I get only "."
The issue makes it unsafe to rely on finalizer for resource cleanup because unrelated finalizer (e.g. from some other library) may prevent your finalizer from running.
Actually I was sure the issue is known, but today I tried to find a reference to it, and failed.
If it is by design, then it should be documented somewhere.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.0.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":"GC and weak reference finalizers and exceptions","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.0.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"When GC runs a number of finalizers in a row, and the first of them throws an exception, then other finalizers are ignored. The relevant piece of code is [https://github.com/ghc/ghc/blob/fb4092642f057f258d07cd6979925f4e2579eda6/libraries/base/GHC/Weak.hs#L144 here].\r\n\r\nThe following program reproduces the issue:\r\n\r\n{{{\r\nimport Data.IORef\r\nimport Control.Monad\r\nimport Control.Exception\r\nimport System.Mem\r\n\r\nmain :: IO ()\r\nmain = do\r\n run\r\n run\r\n run\r\n run\r\n performMajorGC\r\n performMajorGC\r\n\r\nrun :: IO ()\r\nrun = do\r\n ref <- newIORef ()\r\n void $ mkWeakIORef ref $ do\r\n putStr \".\"\r\n throwIO $ ErrorCall \"failed\"\r\n}}}\r\n\r\nI expect it to output \"....\", but I get only \".\"\r\n\r\nThe issue makes it unsafe to rely on finalizer for resource cleanup because unrelated finalizer (e.g. from some other library) may prevent your finalizer from running.\r\n\r\nActually I was sure the issue is known, but today I tried to find a reference to it, and failed.\r\n\r\nIf it is by design, then it should be documented somewhere.","type_of_failure":"OtherFailure","blocking":[]} -->8.6.1https://gitlab.haskell.org/ghc/ghc/-/issues/9717More lazy orphan module loading2022-05-05T04:40:34ZEdward Z. YangMore lazy orphan module loadingCurrently, when we import a module, we eagerly load all of the orphan modules transitively reachable from it (TcRnDriver:tcRnImports). This is a bit of bummer: as module import hierarchies get deeper and deeper, we'll collect more and mo...Currently, when we import a module, we eagerly load all of the orphan modules transitively reachable from it (TcRnDriver:tcRnImports). This is a bit of bummer: as module import hierarchies get deeper and deeper, we'll collect more and more orphan instances and load more and more modules eagerly.
The idea is to try to arrange for an orphan module not to be loaded, unless we think that it might have a relevant instance. Instead of just recording a list of orphan modules transitively reachable from a module, we will also record a digest of what type classes and types the orphan provides instances for. (This will be similar to the data we record for `ifInstTys` in `IfaceClsInst`.)
Now, when we do any operation involving instances, we check and see if there are also orphans which could provide relevant instances (based on the digest) and load those. If an instance could never have been used, we avoid loading its interface file entirely.
This doesn't appear to help too much for type families, where we have to load all of the instances anyway in order to check for consistency.
A choice to make: Should we record just the class, or also the types involved? It would be best if we could quickly conclude that there are no more instances to load, but this may be difficult if matching against types as well.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ----------------------- |
| Version | 7.9 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler (Type checker) |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"More lazy orphan module loading","status":"New","operating_system":"","component":"Compiler (Type checker)","related":[],"milestone":"7.10.1","resolution":"Unresolved","owner":{"tag":"OwnedBy","contents":"ezyang"},"version":"7.9","keywords":["backpack"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Currently, when we import a module, we eagerly load all of the orphan modules transitively reachable from it (TcRnDriver:tcRnImports). This is a bit of bummer: as module import hierarchies get deeper and deeper, we'll collect more and more orphan instances and load more and more modules eagerly.\r\n\r\nThe idea is to try to arrange for an orphan module not to be loaded, unless we think that it might have a relevant instance. Instead of just recording a list of orphan modules transitively reachable from a module, we will also record a digest of what type classes and types the orphan provides instances for. (This will be similar to the data we record for `ifInstTys` in `IfaceClsInst`.)\r\n\r\nNow, when we do any operation involving instances, we check and see if there are also orphans which could provide relevant instances (based on the digest) and load those. If an instance could never have been used, we avoid loading its interface file entirely.\r\n\r\nThis doesn't appear to help too much for type families, where we have to load all of the instances anyway in order to check for consistency.\r\n\r\nA choice to make: Should we record just the class, or also the types involved? It would be best if we could quickly conclude that there are no more instances to load, but this may be difficult if matching against types as well.","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1Edward Z. YangEdward Z. Yanghttps://gitlab.haskell.org/ghc/ghc/-/issues/14677Code generator does not correctly tag a pointer2022-05-04T14:55:55ZSimon Peyton JonesCode generator does not correctly tag a pointerSee also #15155, #16559
Consider
```
data T a = MkT ![a]
```
The pointer stored in a `MkT` constructor should always be correctly tagged, never tagged with un-evaluated 00. C.f. [Commentary/Rts/HaskellExecution/PointerTagging](https:/...See also #15155, #16559
Consider
```
data T a = MkT ![a]
```
The pointer stored in a `MkT` constructor should always be correctly tagged, never tagged with un-evaluated 00. C.f. [Commentary/Rts/HaskellExecution/PointerTagging](https://gitlab.haskell.org/ghc/ghc/wikis/commentary/rts/haskell-execution/pointer-tagging)
But this invariant is broken. Example taken from #14626, #14677-39.
Trac14626_1.hs
```
module Trac14626_1 where
data Style = UserStyle Int
| PprDebug
data SDC = SDC !Style !Int
defaultUserStyle :: Bool -> Style
defaultUserStyle True = UserStyle 123
defaultUserStyle False = PprDebug
```
Trac14626_2.hs
```
module Trac14626_2 where
import Trac14626_1
f :: Int -> SDC
f x = SDC (defaultUserStyle (x > 1)) x
```
Compiling with `ghc Trac14626_1 Trac14626_2 -ddump-simpl -O` results in a similar scenario than the one described by Heisenbug:
```
-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
defaultUserStyle2
defaultUserStyle2 = I# 123#
-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
defaultUserStyle1
defaultUserStyle1 = UserStyle defaultUserStyle2
-- RHS size: {terms: 7, types: 2, coercions: 0, joins: 0/0}
defaultUserStyle
defaultUserStyle
= \ ds_dZ7 ->
case ds_dZ7 of {
False -> PprDebug;
True -> defaultUserStyle1
}
```
Our `UserStyle 123` constant has been lifted to top-level, just like in Heisenbugs example.
Now looking at the Core of `f`
```
f
f = \ x_a1dk ->
case x_a1dk of { I# x1_a2gV ->
case ># x1_a2gV 1# of {
__DEFAULT -> SDC PprDebug x1_a2gV;
1# -> SDC defaultUserStyle1 x1_a2gV
}
}
```
(Note how `f` doesn't scrutinise defaultUserStyle1)
Looking at the CMM for `f` we can see
```
...
if (%MO_S_Le_W64(_s2hT::I64, 1)) goto c2ip; else goto c2is;
c2ip:
I64[Hp - 16] = SDC_con_info;
P64[Hp - 8] = PprDebug_closure+2;
I64[Hp] = _s2hT::I64;
R1 = Hp - 15;
Sp = Sp + 8;
call (P64[Sp])(R1) args: 8, res: 0, upd: 8;
c2is:
I64[Hp - 16] = SDC_con_info;
P64[Hp - 8] = defaultUserStyle1_closure; -- defaultUserStyle1 isn't tagged!
I64[Hp] = _s2hT::I64;
R1 = Hp - 15;
Sp = Sp + 8;
call (P64[Sp])(R1) args: 8, res: 0, upd: 8;
```
When generating code for f the code generator wants to know the `LambdaFormInfo` (the closure type) of `defaultUserStyle1`.
Since `defaultUserStyle1` is defined in another module we end up calling `mkLFImported` in `StgCmmClosure` which ultimatively gives an `LFUnknown` which always gets a `DynTag` 0 from `lfDynTag`.
I think we lack a bit of information here to give defaultUserStyle1 the correct `LFCon` lambda form. Maybe top-level binders should know its `LambdaForm` and include them in their interfaces.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.2.2 |
| 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":"Code generator does not correctly tag a pointer","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.2.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Consider\r\n{{{\r\ndata T a = MkT ![a]\r\n}}}\r\nThe pointer stored in a `MkT` constructor should always be correctly tagged, never tagged with un-evaluated 00. C.f. [wiki:Commentary/Rts/HaskellExecution/PointerTagging]\r\n\r\nBut this invariant is broken. Example taken from #14626, comment:37-39.\r\n\r\nTrac14626_1.hs\r\n{{{\r\nmodule Trac14626_1 where\r\n\r\ndata Style = UserStyle Int\r\n | PprDebug\r\n\r\ndata SDC = SDC !Style !Int\r\n\r\ndefaultUserStyle :: Bool -> Style\r\ndefaultUserStyle True = UserStyle 123\r\ndefaultUserStyle False = PprDebug\r\n}}}\r\n\r\nTrac14626_2.hs\r\n{{{\r\nmodule Trac14626_2 where\r\n\r\nimport Trac14626_1\r\n\r\nf :: Int -> SDC\r\nf x = SDC (defaultUserStyle (x > 1)) x\r\n}}}\r\n\r\nCompiling with `ghc Trac14626_1 Trac14626_2 -ddump-simpl -O` results in a similar scenario than the one described by Heisenbug:\r\n\r\n{{{\r\n-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}\r\ndefaultUserStyle2\r\ndefaultUserStyle2 = I# 123#\r\n\r\n-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}\r\ndefaultUserStyle1\r\ndefaultUserStyle1 = UserStyle defaultUserStyle2\r\n\r\n-- RHS size: {terms: 7, types: 2, coercions: 0, joins: 0/0}\r\ndefaultUserStyle\r\ndefaultUserStyle\r\n = \\ ds_dZ7 ->\r\n case ds_dZ7 of {\r\n False -> PprDebug;\r\n True -> defaultUserStyle1\r\n }\r\n}}}\r\n\r\nOur `UserStyle 123` constant has been lifted to top-level, just like in Heisenbugs example. \r\n\r\nNow looking at the Core of `f`\r\n\r\n{{{\r\nf\r\nf = \\ x_a1dk ->\r\n case x_a1dk of { I# x1_a2gV ->\r\n case ># x1_a2gV 1# of {\r\n __DEFAULT -> SDC PprDebug x1_a2gV;\r\n 1# -> SDC defaultUserStyle1 x1_a2gV\r\n }\r\n }\r\n}}}\r\n\r\n(Note how `f` doesn't scrutinise defaultUserStyle1) \r\n\r\nLooking at the CMM for `f` we can see\r\n\r\n{{{\r\n ... \r\n if (%MO_S_Le_W64(_s2hT::I64, 1)) goto c2ip; else goto c2is;\r\n c2ip:\r\n I64[Hp - 16] = SDC_con_info;\r\n P64[Hp - 8] = PprDebug_closure+2;\r\n I64[Hp] = _s2hT::I64;\r\n R1 = Hp - 15;\r\n Sp = Sp + 8;\r\n call (P64[Sp])(R1) args: 8, res: 0, upd: 8;\r\n c2is:\r\n I64[Hp - 16] = SDC_con_info;\r\n P64[Hp - 8] = defaultUserStyle1_closure; -- defaultUserStyle1 isn't tagged!\r\n I64[Hp] = _s2hT::I64;\r\n R1 = Hp - 15;\r\n Sp = Sp + 8;\r\n call (P64[Sp])(R1) args: 8, res: 0, upd: 8;\r\n\r\n}}}\r\n\r\nWhen generating code for f the code generator wants to know the `LambdaFormInfo` (the closure type) of `defaultUserStyle1`. \r\n\r\nSince `defaultUserStyle1` is defined in another module we end up calling `mkLFImported` in `StgCmmClosure` which ultimatively gives an `LFUnknown` which always gets a `DynTag` 0 from `lfDynTag`. \r\n\r\nI think we lack a bit of information here to give defaultUserStyle1 the correct `LFCon` lambda form. Maybe top-level binders should know its `LambdaForm` and include them in their interfaces. \r\n\r\n\r\n","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/14626No need to enter a scrutinised value2022-05-04T14:55:55ZGabor GreifNo need to enter a scrutinised valueWhile analysing the output of #13861 I stumbled over an unnecessary pessimisation in handling of scrutinised values. With words of Simon (from https://phabricator.haskell.org/D4267 with minor edits added):
Interesting. Yes, please make ...While analysing the output of #13861 I stumbled over an unnecessary pessimisation in handling of scrutinised values. With words of Simon (from https://phabricator.haskell.org/D4267 with minor edits added):
Interesting. Yes, please make a ticket! (And transfer the info below into it.)
I think the issue is this. Given (the STG-ish code)
```hs
data Colour = Red | Green | Blue
f x = case x of y
Red -> Green
DEFAULT -> y
```
(here `y` is the case binder) we can just return `x` rather than entering it in DEFAULT branch, because `y` will be fully evaluated and its pointer will be correctly tagged.
You absolutely can't check for an `OccName` of `"wild"`!! That is neither necessary nor sufficient :-).
Instead, check `isEvaldUnfolding (idUnfolding y)`. See `Note [Preserve evaluatedness]` in `CoreTidy.hs`. And be sure to augment that note if you make the change.
I would expect perf benefits to be small on average, but it's simple to implement.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.2.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | #13861 |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"No need to enter a scrutinised value","status":"New","operating_system":"","component":"Compiler","related":[13861],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.2.2","keywords":["performance"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"While analysing the output of #13861 I stumbled over an unnecessary pessimisation in handling of scrutinised values. With words of Simon (from https://phabricator.haskell.org/D4267 with minor edits added):\r\n\r\nInteresting. Yes, please make a ticket! (And transfer the info below into it.)\r\n\r\nI think the issue is this. Given (the STG-ish code)\r\n{{{#!hs\r\ndata Colour = Red | Green | Blue\r\nf x = case x of y\r\n Red -> Green\r\n DEFAULT -> y\r\n}}}\r\n(here `y` is the case binder) we can just return `x` rather than entering it in DEFAULT branch, because `y` will be fully evaluated and its pointer will be correctly tagged.\r\n\r\n\r\nYou absolutely can't check for an `OccName` of `\"wild\"`!! That is neither necessary nor sufficient :-).\r\n\r\nInstead, check `isEvaldUnfolding (idUnfolding y)`. See `Note [Preserve evaluatedness]` in `CoreTidy.hs`. And be sure to augment that note if you make the change.\r\n\r\nI would expect perf benefits to be small on average, but it's simple to implement.","type_of_failure":"OtherFailure","blocking":[]} -->Gabor GreifGabor Greifhttps://gitlab.haskell.org/ghc/ghc/-/issues/438Recompilation check should include flags2022-05-03T09:14:27ZSimon Peyton JonesRecompilation check should include flags```
GHC skips recompilation of a module if the module code
hasn't changed, even if the flags in use *have* changed.
A benign version is that switching on -O won't recompile
modules that were compiled without -O. But here's a
nastie...```
GHC skips recompilation of a module if the module code
hasn't changed, even if the flags in use *have* changed.
A benign version is that switching on -O won't recompile
modules that were compiled without -O. But here's a
nastier version: changing the -main-is flag can lead to an
obscure link error. Details below supplied by Niels
[cpjvelde@cs.uu.nl]
Simon
Actually, i reproduced it now and the reason is a bit
different. I have an
application Test and Test2. They both have a main
function. Test imports Test2
for some other function. So this is how those files look
like:
~/pancake > cat Test.hs
module Test where
import Test2 hiding (main)
main = doit
~/pancake > cat Test2.hs
module Test2 where
doit = print "Test2.doit"
main = print "Test2.main"
I then first compile the first app:
~/pancake > ghc --make -main-is Test.main Test.hs
Chasing modules from: Test.hs
Compiling Test2 ( ./Test2.hs, ./Test2.o )
Compiling Test ( Test.hs, Test.o )
Linking ...
then i compile the second app:
~/pancake > ghc --make -main-is Test2.main Test2.hs
Chasing modules from: Test2.hs
Skipping Test2 ( Test2.hs, Test2.o )
Linking ...
/usr/lib/ghc-6.4/libHSrts.a(Main.o)(.text+0xe): In function
`main':
: undefined reference to `__stginit_ZCMain'
/usr/lib/ghc-6.4/libHSrts.a(Main.o)(.text+0x28): In
function `main':
: undefined reference to `ZCMain_main_closure'
collect2: ld returned 1 exit status
So I guess generating Test2.o the first time and using -
main-is renamed the main
in Test2.o . Since it is not recompiled when I want to
compile the second app,
it fails because it cant find the main...I thought providing
a -main-is flag
again when compiling the second app would somehow
force recompilation of Test2.o
or at least fixing the 'renaming' that the first compilation
of Test2.o had
caused.
greetings, Niels.
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ----------------- |
| Version | None |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | low |
| Resolution | ResolvedDuplicate |
| Component | None |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Recompilation check should include flags","status":"New","operating_system":"","component":"None","related":[],"milestone":"","resolution":"ResolvedDuplicate","owner":{"tag":"OwnedBy","contents":"nobody"},"version":"None","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"{{{\nGHC skips recompilation of a module if the module code \nhasn't changed, even if the flags in use *have* changed. \nA benign version is that switching on -O won't recompile \nmodules that were compiled without -O. But here's a \nnastier version: changing the -main-is flag can lead to an \nobscure link error. Details below supplied by Niels \n[cpjvelde@cs.uu.nl]\n\nSimon\n\nActually, i reproduced it now and the reason is a bit \ndifferent. I have an\napplication Test and Test2. They both have a main \nfunction. Test imports Test2\nfor some other function. So this is how those files look \nlike:\n\n~/pancake > cat Test.hs\nmodule Test where\nimport Test2 hiding (main)\n\nmain = doit\n\n~/pancake > cat Test2.hs\nmodule Test2 where\n\ndoit = print \"Test2.doit\"\nmain = print \"Test2.main\"\n\nI then first compile the first app:\n~/pancake > ghc --make -main-is Test.main Test.hs\nChasing modules from: Test.hs\nCompiling Test2 ( ./Test2.hs, ./Test2.o )\nCompiling Test ( Test.hs, Test.o )\nLinking ...\n\nthen i compile the second app:\n~/pancake > ghc --make -main-is Test2.main Test2.hs\nChasing modules from: Test2.hs\nSkipping Test2 ( Test2.hs, Test2.o )\nLinking ...\n/usr/lib/ghc-6.4/libHSrts.a(Main.o)(.text+0xe): In function \n`main':\n: undefined reference to `__stginit_ZCMain'\n/usr/lib/ghc-6.4/libHSrts.a(Main.o)(.text+0x28): In \nfunction `main':\n: undefined reference to `ZCMain_main_closure'\ncollect2: ld returned 1 exit status\n\nSo I guess generating Test2.o the first time and using -\nmain-is renamed the main\nin Test2.o . Since it is not recompiled when I want to \ncompile the second app,\nit fails because it cant find the main...I thought providing \na -main-is flag\nagain when compiling the second app would somehow \nforce recompilation of Test2.o\nor at least fixing the 'renaming' that the first compilation \nof Test2.o had \ncaused.\n\ngreetings, Niels.\n\n\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->nobodynobodyhttps://gitlab.haskell.org/ghc/ghc/-/issues/435haddock doesn't like records2022-05-03T09:14:26Zas49haddock doesn't like records```
haddock fails with
~/current/sources/analyzer:$ haddock RecDemo.hs
Warning: RecDemo: the following names could not be
resolved:
Int Bool
Fail: Main.extractRecSel: unexpected (con)declHsConDecl
(SrcLoc 4 13) Foo [] [] [] Nothing...```
haddock fails with
~/current/sources/analyzer:$ haddock RecDemo.hs
Warning: RecDemo: the following names could not be
resolved:
Int Bool
Fail: Main.extractRecSel: unexpected (con)declHsConDecl
(SrcLoc 4 13) Foo [] [] [] Nothing
if a file contains (a) a record constructor with some
field selector elem1, (b) another, non-record
constructor (c) the data type is exported with only the
non-record constructor, (d) the selector elem1 is exported.
Example attached,
Axel.
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------- |
| Version | 6.4 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | ResolvedFixed |
| Component | Documentation |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"haddock doesn't like records","status":"New","operating_system":"","component":"Documentation","related":[],"milestone":"","resolution":"ResolvedFixed","owner":{"tag":"OwnedBy","contents":"nobody"},"version":"6.4","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"{{{\nhaddock fails with\n\n~/current/sources/analyzer:$ haddock RecDemo.hs\nWarning: RecDemo: the following names could not be\nresolved:\n Int Bool\n\nFail: Main.extractRecSel: unexpected (con)declHsConDecl\n(SrcLoc 4 13) Foo [] [] [] Nothing\n\nif a file contains (a) a record constructor with some\nfield selector elem1, (b) another, non-record\nconstructor (c) the data type is exported with only the\nnon-record constructor, (d) the selector elem1 is exported.\n\nExample attached,\nAxel.\n\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->nobodynobodyhttps://gitlab.haskell.org/ghc/ghc/-/issues/9370unfolding info as seen when building a module depends on flags in a previousl...2022-05-02T13:28:50ZCarter Schonwaldunfolding info as seen when building a module depends on flags in a previously-compiled moduleI've observed a blowup in ghc memory usage when invoked with parallel build flags.
to reproduce
```
cabal get xmlhtml-0.2.3.2
cabal install xmlhtml-0.2.3.2 --only-dependencies
cd xmlhtml-0.2.3.2
```
then
```
cabal clean ; cabal con...I've observed a blowup in ghc memory usage when invoked with parallel build flags.
to reproduce
```
cabal get xmlhtml-0.2.3.2
cabal install xmlhtml-0.2.3.2 --only-dependencies
cd xmlhtml-0.2.3.2
```
then
```
cabal clean ; cabal configure --ghc-options="-j4" ; time cabal build -j4 -v3
```
will take quite a while and use \> 1gb of ram
whereas
```
cabal clean ; cabal configure --ghc-options="-j1 ; time cabal build -j1 -v3
```
will use \< 150mb of ram.
Based upon the output of cabal build -j4 -v3, it looks like the parallel build is spending a lottt more time in the simplifier passes. I'm not sure what changes between the parallel and sequential builds to change this. I'll try to dig into this more in a few days, but recording this problem now before i forget. (though of course any insights would be appreciated)
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.8.3 |
| 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":"large blowup in memory usage and time when doing parallel build of xmlhtml package","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.8.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"I've observed a blowup in ghc memory usage when invoked with parallel build flags.\r\n\r\nto reproduce \r\n\r\n{{{\r\ncabal get xmlhtml-0.2.3.2\r\ncabal install xmlhtml-0.2.3.2 --only-dependencies\r\ncd xmlhtml-0.2.3.2 \r\n}}}\r\n\r\nthen \r\n{{{\r\n cabal clean ; cabal configure --ghc-options=\"-j4\" ; time cabal build -j4 -v3\r\n}}}\r\nwill take quite a while and use > 1gb of ram\r\n\r\nwhereas \r\n\r\n{{{\r\n cabal clean ; cabal configure --ghc-options=\"-j1 ; time cabal build -j1 -v3\r\n\r\n}}}\r\n\r\nwill use < 150mb of ram.\r\n\r\nBased upon the output of cabal build -j4 -v3, it looks like the parallel build is spending a lottt more time in the simplifier passes. I'm not sure what changes between the parallel and sequential builds to change this. I'll try to dig into this more in a few days, but recording this problem now before i forget. (though of course any insights would be appreciated)","type_of_failure":"OtherFailure","blocking":[]} -->Matthew PickeringMatthew Pickeringhttps://gitlab.haskell.org/ghc/ghc/-/issues/1349Generalise the ! and UNPACK mechanism for data types, to unpack function argu...2022-05-02T10:14:44ZSimon Peyton JonesGeneralise the ! and UNPACK mechanism for data types, to unpack function argumentsSee this thread:
> http://www.nabble.com/More-speed-please!-t3411977.html
Briefly the idea is to allow
```
data T = MkT (!Int -> Bool)
```
to make a `MkT` hold strict functions only. Anyone unpacking a `MkT` can assume the functio...See this thread:
> http://www.nabble.com/More-speed-please!-t3411977.html
Briefly the idea is to allow
```
data T = MkT (!Int -> Bool)
```
to make a `MkT` hold strict functions only. Anyone unpacking a `MkT` can assume the function is strict; and anyone building a `MkT` gets a strictness wrapper aound whatever function they supply, so even if they supply a lazy function, it's made strict.
Seems like a natural generalisation of the existing strictness and UNPACK mechanism for data types.
Lots of details in the thread above.
Simon8.0.1https://gitlab.haskell.org/ghc/ghc/-/issues/932Improve inlining2022-05-02T10:02:52ZSimon Peyton JonesImprove inliningCurrently the contruct
```
case (x# ># 0#) of ...
```
attracts no argument discount for x\#, which is silly.
The comment in CoreUnfold says:
```
PrimOpId op -> primOpSize op (valArgCount args)
-- foldr addSize (primOpSize ...Currently the contruct
```
case (x# ># 0#) of ...
```
attracts no argument discount for x\#, which is silly.
The comment in CoreUnfold says:
```
PrimOpId op -> primOpSize op (valArgCount args)
-- foldr addSize (primOpSize op) (map arg_discount args)
-- At one time I tried giving an arg-discount if a primop
-- is applied to one of the function's arguments, but it's
-- not good. At the moment, any unlifted-type arg gets a
-- 'True' for 'yes I'm evald', so we collect the discount even
-- if we know nothing about it. And just having it in a primop
-- doesn't help at all if we don't know something more.
```
But the right thing to do seems to be to fix interestingArg in SimplUtils so that it only thinks a primitive-typed thing is interesting if it knows its value (or some structure).
Here's the program that triggered this thought:
```
import GHC.Word
import GHC.Base
import GHC.Prim
a `shiftRLT` b | b >=# 32# = int2Word# 0#
| otherwise = a `uncheckedShiftRL#` b
(W32# x#) `shift` (I# i#) =
{- we do an actual case analysis on i# to try to give us a discount -}
case i# of
{- For some bizzare reason removing the `shiftRLT` 0# makes the
inlining fail again -}
0# -> W32# (x# `shiftRLT` 0#)
_ ->
if i# >=# 0# then W32# (narrow32Word# (x# `shiftL#` i#))
else W32# (x# `shiftRLT` negateInt# i#)
x `shiftR` y = x `shift` (-y)
shift7 x = x `shiftR` 7
```
roconnor\@theorem.ca initiated the thread
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 6.4.2 |
| Type | Task |
| 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 inlining","status":"New","operating_system":"Unknown","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.4.2","keywords":[],"differentials":[],"test_case":"","architecture":"Unknown","cc":[""],"type":"Task","description":"Currently the contruct\r\n{{{\r\n case (x# ># 0#) of ...\r\n}}}\r\nattracts no argument discount for x#, which is silly.\r\n\r\nThe comment in CoreUnfold says:\r\n{{{\r\n\t PrimOpId op -> primOpSize op (valArgCount args)\r\n\t\t\t -- foldr addSize (primOpSize op) (map arg_discount args)\r\n\t\t\t -- At one time I tried giving an arg-discount if a primop \r\n\t\t\t -- is applied to one of the function's arguments, but it's\r\n\t\t\t -- not good. At the moment, any unlifted-type arg gets a\r\n\t\t\t -- 'True' for 'yes I'm evald', so we collect the discount even\r\n\t\t\t -- if we know nothing about it. And just having it in a primop\r\n\t\t\t -- doesn't help at all if we don't know something more.\r\n}}}\r\nBut the right thing to do seems to be to fix interestingArg in SimplUtils so that it only thinks a primitive-typed thing is interesting if it knows its value (or some structure).\r\n\r\nHere's the program that triggered this thought:\r\n{{{\r\nimport GHC.Word\r\nimport GHC.Base\r\nimport GHC.Prim\r\n\r\na `shiftRLT` b | b >=# 32# = int2Word# 0#\r\n | otherwise = a `uncheckedShiftRL#` b\r\n\r\n(W32# x#) `shift` (I# i#) =\r\n{- we do an actual case analysis on i# to try to give us a discount -}\r\n case i# of\r\n {- For some bizzare reason removing the `shiftRLT` 0# makes the\r\n inlining fail again -}\r\n 0# -> W32# (x# `shiftRLT` 0#)\r\n _ -> \r\n\t if i# >=# 0# then W32# (narrow32Word# (x# `shiftL#` i#))\r\n else W32# (x# `shiftRLT` negateInt# i#)\r\n\r\nx `shiftR` y = x `shift` (-y)\r\n\r\nshift7 x = x `shiftR` 7\r\n}}}\r\nroconnor@theorem.ca initiated the thread","type_of_failure":"OtherFailure","blocking":[]} -->Simon Peyton JonesSimon Peyton Joneshttps://gitlab.haskell.org/ghc/ghc/-/issues/2968Avoid generating C trigraphs2022-05-01T13:27:41ZduncanAvoid generating C trigraphs```
main = print "??)"
```
If we compile the above with an `unregisterised` ghc then some gcc versions report:
```
/tmp/ghc6084_0/ghc6084_0.hc:99:30:
warning: trigraph ??) ignored, use -trigraphs to enable
```
This should make us...```
main = print "??)"
```
If we compile the above with an `unregisterised` ghc then some gcc versions report:
```
/tmp/ghc6084_0/ghc6084_0.hc:99:30:
warning: trigraph ??) ignored, use -trigraphs to enable
```
This should make us nervous.
According to the GCC manual if we were ever to use `-std=c89` or any of the official C standard compliance modes (ie non-GNU) then we would get standard C (cpp) trigraph behavior.
We should therefore add a codeGen/should_run test to make sure that the above program does always print `"??)"` and never `"]"`. This test only needs to be run in `unregisterised` mode.
It's not an immediate priority but it may trip someone up in future when porting or if we make unregisterised C code more standards compliant and start using one of the official `-std=` modes. It is unlikely to hit us but if it ever did it'd be a real pain to debug.
Edit: replaced `-fvia-c` by [unregisterised](building/unregisterised) (see 392b7e2a34d26b01ca65648eb5b4a078b0a64e69).8.0.1kchugalinskiykchugalinskiyhttps://gitlab.haskell.org/ghc/ghc/-/issues/3541Allow local foreign imports2022-05-01T11:19:23ZmokusAllow local foreign importsI have no idea the level of difficulty this would entail, but it would be rather nice to be able to import foreign functions at scopes other than the top level. When writing glue code, especially for C++ where I often want to catch and h...I have no idea the level of difficulty this would entail, but it would be rather nice to be able to import foreign functions at scopes other than the top level. When writing glue code, especially for C++ where I often want to catch and haskellize exceptions, I find myself using wrappers quite a bit, for example:
```
foreign import ccall "foo.h foo"
raw_foo :: CString -> IO ()
foo :: String -> IO ()
foo s = withCString s raw_foo
```
Where I only want "foo" exported from the module. It's not that big a deal to list explicit exports, I know, but I would like to be able to say instead:
```
foo :: String -> IO ()
foo s = withCString s raw_foo
where
foreign import ccall "foo.h foo" raw_foo :: CString -> IO ()
```
In addition to reducing clutter in the top level namespace, it makes for less clutter on the left margin of the code, making it easier to scan through function names visually.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 6.10.4 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler (FFI) |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Allow local foreign imports","status":"New","operating_system":"","component":"Compiler (FFI)","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.10.4","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"I have no idea the level of difficulty this would entail, but it would be rather nice to be able to import foreign functions at scopes other than the top level. When writing glue code, especially for C++ where I often want to catch and haskellize exceptions, I find myself using wrappers quite a bit, for example:\r\n\r\n{{{\r\nforeign import ccall \"foo.h foo\" \r\n raw_foo :: CString -> IO ()\r\nfoo :: String -> IO ()\r\nfoo s = withCString s raw_foo\r\n}}}\r\n\r\nWhere I only want \"foo\" exported from the module. It's not that big a deal to list explicit exports, I know, but I would like to be able to say instead:\r\n\r\n{{{\r\nfoo :: String -> IO ()\r\nfoo s = withCString s raw_foo\r\n where\r\n foreign import ccall \"foo.h foo\" raw_foo :: CString -> IO ()\r\n}}}\r\n\r\nIn addition to reducing clutter in the top level namespace, it makes for less clutter on the left margin of the code, making it easier to scan through function names visually.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/3085warn about language extensions that are not used2022-05-01T11:07:49ZPVerswyvelenwarn about language extensions that are not usedWhen I put
`{-# OPTIONS_GHC -Wall -Werror #-}`
in my source file, I don't get compiler warnings about redundant language extensions that I enabled in that file.
For example if I write
`{-# LANGUAGE GeneralizedNewtypeDeriving #-}`
in...When I put
`{-# OPTIONS_GHC -Wall -Werror #-}`
in my source file, I don't get compiler warnings about redundant language extensions that I enabled in that file.
For example if I write
`{-# LANGUAGE GeneralizedNewtypeDeriving #-}`
in the file, but I never do newtype deriving, the compiler could give me a warning.
It would be nice if the compiler gave warnings about this, since after refactoring, some language extensions might not be needed anymore, and hence should be removed since fewer language extensions mean more stable and portable code no?
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 6.10.1 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"warn about language extensions that are not used","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.10.1","keywords":["extensions","language","warnings"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"When I put\r\n\r\n`{-# OPTIONS_GHC -Wall -Werror #-}`\r\n\r\nin my source file, I don't get compiler warnings about redundant language extensions that I enabled in that file.\r\n\r\nFor example if I write\r\n\r\n`{-# LANGUAGE GeneralizedNewtypeDeriving #-}`\r\n\r\nin the file, but I never do newtype deriving, the compiler could give me a warning.\r\n\r\nIt would be nice if the compiler gave warnings about this, since after refactoring, some language extensions might not be needed anymore, and hence should be removed since fewer language extensions mean more stable and portable code no?\r\n\r\n","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1https://gitlab.haskell.org/ghc/ghc/-/issues/1012ghc panic with mutually recursive modules and template haskell2022-05-01T10:46:12Zguestghc panic with mutually recursive modules and template haskellWhen compiling the files below using ghc --make Main.hs I get the following error:
```
[1 of 5] Compiling ModuleA[boot] ( ModuleA.hs-boot, nothing )
[2 of 5] Compiling ModuleC ( ModuleC.hs, ModuleC.o )
[3 of 5] Compiling Mod...When compiling the files below using ghc --make Main.hs I get the following error:
```
[1 of 5] Compiling ModuleA[boot] ( ModuleA.hs-boot, nothing )
[2 of 5] Compiling ModuleC ( ModuleC.hs, ModuleC.o )
[3 of 5] Compiling ModuleB ( ModuleB.hs, ModuleB.o )
Loading package base ... linking ... done.
Loading package template-haskell ... linking ... done.
ghc-6.6: panic! (the 'impossible' happened)
(GHC version 6.6 for powerpc-apple-darwin):
Maybe.fromJust: Nothing
```
ModuleA.hs:
```
module ModuleA where
import ModuleB
```
ModuleA.hs-boot:
```
module ModuleA where
```
ModuleB.hs:
```
{-# OPTIONS -fth #-}
module ModuleB where
import ModuleC
$(nothing)
```
ModuleC.hs:
```
module ModuleC where
import Language.Haskell.TH
import {-# SOURCE #-} ModuleA
nothing = return [] :: Q [Dec]
```
Main.hs:
```
module Main.hs
import ModuleA
main = return ()
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 6.6 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | MacOS X |
| Architecture | powerpc |
</details>
<!-- {"blocked_by":[],"summary":"ghc panic with mutually recursive modules and template haskell","status":"New","operating_system":"MacOS X","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.6","keywords":[],"differentials":[],"test_case":"","architecture":"powerpc","cc":[""],"type":"Bug","description":"When compiling the files below using ghc --make Main.hs I get the following error:\r\n{{{\r\n[1 of 5] Compiling ModuleA[boot] ( ModuleA.hs-boot, nothing )\r\n[2 of 5] Compiling ModuleC ( ModuleC.hs, ModuleC.o )\r\n[3 of 5] Compiling ModuleB ( ModuleB.hs, ModuleB.o )\r\nLoading package base ... linking ... done.\r\nLoading package template-haskell ... linking ... done.\r\nghc-6.6: panic! (the 'impossible' happened)\r\n (GHC version 6.6 for powerpc-apple-darwin):\r\n Maybe.fromJust: Nothing\r\n}}}\r\n\r\n\r\nModuleA.hs:\r\n{{{\r\nmodule ModuleA where\r\n\r\nimport ModuleB\r\n}}}\r\n\r\nModuleA.hs-boot:\r\n{{{\r\nmodule ModuleA where\r\n}}}\r\n\r\nModuleB.hs:\r\n{{{\r\n{-# OPTIONS -fth #-}\r\nmodule ModuleB where\r\n\r\nimport ModuleC\r\n\r\n$(nothing)\r\n}}}\r\n\r\nModuleC.hs:\r\n{{{\r\nmodule ModuleC where\r\n\r\nimport Language.Haskell.TH\r\n\r\nimport {-# SOURCE #-} ModuleA\r\n\r\nnothing = return [] :: Q [Dec]\r\n}}}\r\n\r\nMain.hs:\r\n{{{\r\nmodule Main.hs\r\n\r\nimport ModuleA\r\n\r\nmain = return ()\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1https://gitlab.haskell.org/ghc/ghc/-/issues/2182GHC sessions (--make, --interactive, GHC API) erroneously retain instances2022-04-29T16:54:26Zclaus.reinke@talk21.comGHC sessions (--make, --interactive, GHC API) erroneously retain instancesThe EPS (external-package state) is only ever increased, never decreased between compilation of different modules in a single batch compilation or GHCi session.
Example 1 (GHCi):
```
ezyang@sabre:~/Dev/labs/ezyangest$ ghci
GHCi, versio...The EPS (external-package state) is only ever increased, never decreased between compilation of different modules in a single batch compilation or GHCi session.
Example 1 (GHCi):
```
ezyang@sabre:~/Dev/labs/ezyangest$ ghci
GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> (\x -> x)
<interactive>:2:1:
No instance for (Show (t0 -> t0)) arising from a use of `print'
Possible fix: add an instance declaration for (Show (t0 -> t0))
In a stmt of an interactive GHCi command: print it
Prelude> :m +Text.Show.Functions
Prelude Text.Show.Functions> (\x -> x)
<function>
Prelude Text.Show.Functions> :m -Text.Show.Functions
Prelude> :r
Ok, modules loaded: none.
Prelude> (\x -> x)
<function>
```
Example 2 (make):
```
ezyang@sabre:~/Dev/labs/ezyangest$ cat A.hs
module A where
import Text.Show.Functions
ezyang@sabre:~/Dev/labs/ezyangest$ cat B.hs
module B where
y = show (\x -> x)
ezyang@sabre:~/Dev/labs/ezyangest$ ghc --make B.hs A.hs
[1 of 2] Compiling A ( A.hs, A.o )
[2 of 2] Compiling B ( B.hs, B.o )
ezyang@sabre:~/Dev/labs/ezyangest$ ghc --make A.hs B.hs -fforce-recomp
[1 of 2] Compiling B ( B.hs, B.o )
B.hs:2:5:
No instance for (Show (t0 -> t0)) arising from a use of `show'
Possible fix: add an instance declaration for (Show (t0 -> t0))
In the expression: show (\ x -> x)
In an equation for `y': y = show (\ x -> x)
```7.10.1Edward Z. YangEdward Z. Yanghttps://gitlab.haskell.org/ghc/ghc/-/issues/16243Improve fregs-graph.2022-04-29T11:08:40ZAndreas KlebingerImprove fregs-graph.I'm creating this as a way to keep track of shortcomings of the current implementation.
Some of these are directly taken from TODOS, other are my own opinions.
# Things that could be looked at.
## Compress spill slots.
Currently we a...I'm creating this as a way to keep track of shortcomings of the current implementation.
Some of these are directly taken from TODOS, other are my own opinions.
# Things that could be looked at.
## Compress spill slots.
Currently we assign each vreg a fixed spill slot. This is terrible for cache performance.
It's possible to end up with sequences like this:
```asm
block_ca01_info:
_ca01:
movq 16(%rbp),%r14
movq 24(%rbp),%rax
movq %rax,144(%rsp)
movq 32(%rbp),%rsi
movq 40(%rbp),%rdi
movq 64(%rbp),%rbx
movq 56(%rbp),%rax
movq %rax,208(%rsp)
movq 48(%rbp),%rax
movq %rax,168(%rsp)
movq 8(%rbp),%rax
movq %rax,216(%rsp)
addq $8,%rbp
```
Which splits spill slots over multiple cache lines increasing cache pressure.
Things possibly worth trying:
- Assign spill slots in the order they appear - hopefully reducing the average spread within code blocks.
- Dynamically assign vregs to spill slots.
For the later if we have large independent subgraphs we will sometimes get away with using far fewer slots.
The reason simply being that non overlapping vregs can share spill slots.
Doing this in an efficient manner however isn't easy.
## We sometimes load + spill vregs when we could use memory addressing.
One example I've seen a few times in nofib is this:
```
movq 208(%rsp),%rax
incq %rax
movq %rax,208(%rsp)
```
Which we should replace with a single `inc` operating on memory.
## Lift the stack size limit.
There is already a patch [in flight](https://gitlab.haskell.org/ghc/ghc/merge_requests/219).
## Revisit spill costs.
Currently the allocator always spills the longest live range. Which often works but is certainly not a great metric.
Ideas:
### Consider loop membership.
At least for x86/64 this would be easy to achieve on basic block granularity using the CFG that is also used for block layout.
### Revisit chaitins cost model.
There have been major changes to cpus (amd64 becoming the norm) and the backend
so at a minimum this cost model should be reevaluated.
## Try splitting long live ranges instead of simply spilling the complete live range.
After all long live ranges were the original reason to switch to a life range only based cost heuristic.
## Use a different spill algorithm altogether.
Maybe Chows live range splitting based approach would be an option.
See "The priority based coloring approach to register allocation" for details.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------------ |
| Version | 8.6.3 |
| Type | Task |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler (CodeGen) |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Improve fregs-graph.","status":"New","operating_system":"","component":"Compiler (CodeGen)","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.3","keywords":["fregs-graph"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Task","description":"I'm creating this as a way to keep track of shortcomings of the current implementation.\r\n\r\nSome of these are directly taken from TODOS, other are my own opinions.\r\n\r\n= Things that could be looked at.\r\n\r\n== Compress spill slots.\r\n\r\nCurrently we assign each vreg a fixed spill slot. This is terrible for cache performance.\r\n\r\nIt's possible to end up with sequences like this:\r\n\r\n{{{#!asm\r\nblock_ca01_info:\r\n_ca01:\r\n\tmovq 16(%rbp),%r14\r\n\tmovq 24(%rbp),%rax\r\n\tmovq %rax,144(%rsp)\r\n\tmovq 32(%rbp),%rsi\r\n\tmovq 40(%rbp),%rdi\r\n\tmovq 64(%rbp),%rbx\r\n\tmovq 56(%rbp),%rax\r\n\tmovq %rax,208(%rsp)\r\n\tmovq 48(%rbp),%rax\r\n\tmovq %rax,168(%rsp)\r\n\tmovq 8(%rbp),%rax\r\n\tmovq %rax,216(%rsp)\r\n\taddq $8,%rbp\r\n}}}\r\n\r\nWhich splits spill slots over multiple cache lines increasing cache pressure.\r\n\r\nThings possibly worth trying:\r\n\r\n* Assign spill slots in the order they appear - hopefully reducing the average spread within code blocks.\r\n* Dynamically assign vregs to spill slots.\r\n\r\nFor the later if we have large independent subgraphs we will sometimes get away with using far fewer slots. \r\nThe reason simply being that non overlapping vregs can share spill slots.\r\n\r\nDoing this in an efficient manner however isn't easy.\r\n\r\n== We sometimes load + spill vregs when we could use memory addressing.\r\n\r\nOne example I've seen a few times in nofib is this:\r\n{{{\r\n\tmovq 208(%rsp),%rax\r\n\tincq %rax\r\n\tmovq %rax,208(%rsp)\r\n}}}\r\n\r\nWhich we should replace with a single `inc` operating on memory.\r\n\r\n== Lift the stack size limit.\r\n\r\nThere is already a patch [https://gitlab.haskell.org/ghc/ghc/merge_requests/219 in flight].\r\n\r\n== Revisit spill costs.\r\n\r\nCurrently the allocator always spills the longest live range. Which often works but is certainly not a great metric.\r\n\r\nIdeas:\r\n\r\n=== Consider loop membership.\r\n\r\nAt least for x86/64 this would be easy to achieve on basic block granularity using the CFG that is also used for block layout.\r\n\r\n=== Revisit chaitins cost model.\r\n\r\nThere have been major changes to cpus (amd64 becoming the norm) and the backend\r\nso at a minimum this cost model should be reevaluated.\r\n\r\n== Try splitting long live ranges instead of simply spilling the complete live range.\r\n\r\nAfter all long live ranges were the original reason to switch to a life range only based cost heuristic.\r\n\r\n== Use a different spill algorithm altogether.\r\n\r\nMaybe Chows live range splitting based approach would be an option.\r\nSee \"The priority based coloring approach to register allocation\" for details.\r\n\r\n\r\n\r\n\r\n","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/7094Irrefutable pattern failed for pattern Data.Maybe.Just2022-04-29T10:39:00ZpganelinIrrefutable pattern failed for pattern Data.Maybe.JustThe following invalid program causes ghc panic
```
-----------------------
--State-Monad.hs
data Term = Con Int
| Div Term Term
deriving (Show)
type M a = State -> (a,State)
type State =Int
instance Monad Int -> (a,Int) wh...The following invalid program causes ghc panic
```
-----------------------
--State-Monad.hs
data Term = Con Int
| Div Term Term
deriving (Show)
type M a = State -> (a,State)
type State =Int
instance Monad Int -> (a,Int) where
g >>= f = undefined
return = undefined
-------------------------------
```
```
D:\>"C:\Free\Haskell Platform\2012.2.0.0\bin\ghc.exe" D:\State-Monad.hs
[1 of 1] Compiling Main ( D:\State-Monad.hs, D:\State-Monad.o )
ghc.exe: panic! (the 'impossible' happened)
(GHC version 7.4.1 for i386-unknown-mingw32):
compiler\rename\RnSource.lhs:429:14-81: Irrefutable pattern failed for pattern Data.Maybe.Just (inst_tyvars,
_,
SrcLoc.L _ cls,
_)
Please report this as a GHC bug: http://www.haskell.org/ghc/reportabug
```7.6.1https://gitlab.haskell.org/ghc/ghc/-/issues/8272Consider using native stack pointer register for STG stack2022-04-28T15:51:32ZCarter SchonwaldConsider using native stack pointer register for STG stackThere are a variety of reasons why we might want to use the native stack pointer register to track the STG stack:
* Performance might be better for a variety of reasons:
* we could possibly use `PUSH` instead of `MOV` on x86, which ...There are a variety of reasons why we might want to use the native stack pointer register to track the STG stack:
* Performance might be better for a variety of reasons:
* we could possibly use `PUSH` instead of `MOV` on x86, which has a more succinct encoding
* the LLVM backend would be able to make better assumptions about pointer aliasing(?)
* microarchitecture implementations likely optimise for stack accesses
* In conjunction with DWARF debug information we could more easily use `perf` and other performance measurement tools (e.g. #15929)
https://gitlab.haskell.org/ghc/ghc/-/issues/15375GHC.Exts.Heap.getClosureData doesn't return the payload for AP_STACK2022-04-27T23:35:18ZSimon MarlowGHC.Exts.Heap.getClosureData doesn't return the payload for AP_STACKSee [D4955](https://phabricator.haskell.org/D4955)
We used to return the payload, but a stack is a mixture of pointers and non-pointers, so this was bogus. In [D4955](https://phabricator.haskell.org/D4955) I changed it to ignore the pay...See [D4955](https://phabricator.haskell.org/D4955)
We used to return the payload, but a stack is a mixture of pointers and non-pointers, so this was bogus. In [D4955](https://phabricator.haskell.org/D4955) I changed it to ignore the payload, so now at least it doesn't crash, but we don't have any payload info.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 8.4.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | low |
| Resolution | Unresolved |
| Component | Runtime System |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"GHC.Exts.Heap.getClosureData doesn't return the payload for AP_STACK","status":"New","operating_system":"","component":"Runtime System","related":[],"milestone":"8.6.1","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.4.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"See Phab:D4955\r\n\r\nWe used to return the payload, but a stack is a mixture of pointers and non-pointers, so this was bogus. In Phab:D4955 I changed it to ignore the payload, so now at least it doesn't crash, but we don't have any payload info.","type_of_failure":"OtherFailure","blocking":[]} -->9.2.1https://gitlab.haskell.org/ghc/ghc/-/issues/14444Linker limit on OS X Sierra breaks builds for big projects2022-04-27T20:56:31ZdredozubovLinker limit on OS X Sierra breaks builds for big projectsI'm opening a fresh ticket as \@bgamari suggested in #12479. There are few more related closed tickets as well: #12198 and #12588. The issue occurs on projects with a lot of dependencies. There are reports of that happening across variou...I'm opening a fresh ticket as \@bgamari suggested in #12479. There are few more related closed tickets as well: #12198 and #12588. The issue occurs on projects with a lot of dependencies. There are reports of that happening across various projects:
[https://github.com/NixOS/nixpkgs/issues/22810](https://github.com/NixOS/nixpkgs/issues/22810)
[https://github.com/commercialhaskell/stack/issues/2577](https://github.com/commercialhaskell/stack/issues/2577)
I'm still able to reproduce it with 8.2.1 and git HEAD with a work project:
```
ghc: panic! (the 'impossible' happened)
(GHC version 8.2.1 for x86_64-apple-darwin):
Loading temp shared object failed: dlopen(/var/folders/f8/2_rc4tgd1gj9vbgv7q9gbk4c0000gn/T/ghc94377_0/libghc_325.dylib, 5): no suitable image found. Did find:
/var/folders/f8/2_rc4tgd1gj9vbgv7q9gbk4c0000gn/T/ghc94377_0/libghc_325.dylib: malformed mach-o: load commands size (34592) > 32768
Please report this as a GHC bug: http://www.haskell.org/ghc/reportabug
```
I can't share the sources, but this is a command(generated by stack) that results in this error:
`/Users/dr/.stack/setup-exe-cache/x86_64-osx/Cabal-simple_mPHDZzAJ_2.0.0.2_ghc-8.2.1 --builddir=.stack-work/dist/x86_64-osx/Cabal-2.0.0.2 build lib:projectname exe:projectname --ghc-options " -ddump-hi -ddump-to-file -fdiagnostics-color=always"`
We're having a chat about this issue with \@bgamari and I'll post some of his input:
```
bgamari: dredozubov, unfortunately this is pretty much a limitation of OS X's linker
bgamari: there's no great solution other than petitioning Apple to lift their arbitrary size limit
bgamari: I've been asking people to open tickets with Apple
bgamari: As they are really the only ones that can really fix this issue
dredozubov: bgamari, do you know if someone did this already?
bgamari: dredozubov, No one has said they have
dredozubov: the other issue with it, I don't how to do a repro case
dredozubov: I can reproduce it on a project with a closed sources and that's it
bgamari: essentially you just need to build a project with enough dependencies
bgamari: the problem is that Apple's linker sets an artificial cap on the number of shared libraries that an object file can load
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------------ |
| Version | 8.2.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler (Linking) |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Linker limit on OS X Sierra breaks builds for big projects","status":"New","operating_system":"","component":"Compiler (Linking)","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.2.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"I'm opening a fresh ticket as @bgamari suggested in #12479. There are few more related closed tickets as well: #12198 and #12588. The issue occurs on projects with a lot of dependencies. There are reports of that happening across various projects:\r\n\r\n[https://github.com/NixOS/nixpkgs/issues/22810]\r\n[https://github.com/commercialhaskell/stack/issues/2577]\r\n\r\nI'm still able to reproduce it with 8.2.1 and git HEAD with a work project:\r\n{{{\r\n ghc: panic! (the 'impossible' happened)\r\n (GHC version 8.2.1 for x86_64-apple-darwin):\r\n \tLoading temp shared object failed: dlopen(/var/folders/f8/2_rc4tgd1gj9vbgv7q9gbk4c0000gn/T/ghc94377_0/libghc_325.dylib, 5): no suitable image found. Did find:\r\n \t/var/folders/f8/2_rc4tgd1gj9vbgv7q9gbk4c0000gn/T/ghc94377_0/libghc_325.dylib: malformed mach-o: load commands size (34592) > 32768\r\n\r\n Please report this as a GHC bug: http://www.haskell.org/ghc/reportabug\r\n}}}\r\n\r\nI can't share the sources, but this is a command(generated by stack) that results in this error:\r\n\r\n`/Users/dr/.stack/setup-exe-cache/x86_64-osx/Cabal-simple_mPHDZzAJ_2.0.0.2_ghc-8.2.1 --builddir=.stack-work/dist/x86_64-osx/Cabal-2.0.0.2 build lib:projectname exe:projectname --ghc-options \" -ddump-hi -ddump-to-file -fdiagnostics-color=always\"`\r\n\r\nWe're having a chat about this issue with @bgamari and I'll post some of his input:\r\n{{{\r\n bgamari: dredozubov, unfortunately this is pretty much a limitation of OS X's linker\r\n bgamari: there's no great solution other than petitioning Apple to lift their arbitrary size limit\r\n bgamari: I've been asking people to open tickets with Apple\r\n bgamari: As they are really the only ones that can really fix this issue\r\n dredozubov: bgamari, do you know if someone did this already?\r\n bgamari: dredozubov, No one has said they have\r\n dredozubov: the other issue with it, I don't how to do a repro case\r\n dredozubov: I can reproduce it on a project with a closed sources and that's it\r\n bgamari: essentially you just need to build a project with enough dependencies\r\n bgamari: the problem is that Apple's linker sets an artificial cap on the number of shared libraries that an object file can load\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->8.6.1Moritz AngermannMoritz Angermannhttps://gitlab.haskell.org/ghc/ghc/-/issues/11950Eventlog should include delimiters showing when the process writes to the .ev...2022-04-27T18:00:16ZJamesFisherEventlog should include delimiters showing when the process writes to the .eventlog fileQuoting a comment I just added at https://ghc.haskell.org/trac/ghc/wiki/EventLog\#Limitations :
> Event logging can produce "observer effects". In particular, programs can pause while writing to the `.eventlog` file. These display in Th...Quoting a comment I just added at https://ghc.haskell.org/trac/ghc/wiki/EventLog\#Limitations :
> Event logging can produce "observer effects". In particular, programs can pause while writing to the `.eventlog` file. These display in Threadscope as periods of 100% CPU use with no obvious cause. This effect is exacerbated by heavy use of debug tools which expand the eventlog file, such as `Trace.traceMarkerIO`. (This effect was at least seen on OS X. In an extreme case, a program doing nothing but writing 200,000 trace markers, which took 120 ms to run, showed a single 10ms pause in the middle to write them to the `.eventlog` file. These periods were shown to be due to writing the `.eventlog` file by using `dtruss -a`, which shows long periods of `write_nocancel` syscalls, writing to the `.eventlog` file opened earlier with `open_nocancel`.)
This behavior caused a few hours of investigation for us. It would make it much more obvious what is happening if this behavior were logged in the eventlog. Specifically, I would like for the eventlog to include a "starting writing eventlog file" event at the start of each of these periods, and a "stopped" event at the end of each period.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.10.3 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Runtime System |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | simonmar |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Eventlog should include delimiters showing when the process writes to the .eventlog file","status":"New","operating_system":"","component":"Runtime System","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.10.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":["simonmar"],"type":"FeatureRequest","description":"Quoting a comment I just added at https://ghc.haskell.org/trac/ghc/wiki/EventLog#Limitations :\r\n\r\n> Event logging can produce \"observer effects\". In particular, programs can pause while writing to the `.eventlog` file. These display in Threadscope as periods of 100% CPU use with no obvious cause. This effect is exacerbated by heavy use of debug tools which expand the eventlog file, such as `Trace.traceMarkerIO`. (This effect was at least seen on OS X. In an extreme case, a program doing nothing but writing 200,000 trace markers, which took 120 ms to run, showed a single 10ms pause in the middle to write them to the `.eventlog` file. These periods were shown to be due to writing the `.eventlog` file by using `dtruss -a`, which shows long periods of `write_nocancel` syscalls, writing to the `.eventlog` file opened earlier with `open_nocancel`.)\r\n\r\nThis behavior caused a few hours of investigation for us. It would make it much more obvious what is happening if this behavior were logged in the eventlog. Specifically, I would like for the eventlog to include a \"starting writing eventlog file\" event at the start of each of these periods, and a \"stopped\" event at the end of each period.","type_of_failure":"OtherFailure","blocking":[]} -->