{"action":"closed","issue":{"url":"https://api.github.com/repos/clash-lang/clash-compiler/issues/399","repository_url":"https://api.github.com/repos/clash-lang/clash-compiler","labels_url":"https://api.github.com/repos/clash-lang/clash-compiler/issues/399/labels{/name}","comments_url":"https://api.github.com/repos/clash-lang/clash-compiler/issues/399/comments","events_url":"https://api.github.com/repos/clash-lang/clash-compiler/issues/399/events","html_url":"https://github.com/clash-lang/clash-compiler/issues/399","id":376058128,"node_id":"MDU6SXNzdWUzNzYwNTgxMjg=","number":399,"title":"HiddenClockReset gets specialized away by GHC?","user":{"login":"leonschoorl","id":437852,"node_id":"MDQ6VXNlcjQzNzg1Mg==","avatar_url":"https://avatars1.githubusercontent.com/u/437852?v=4","gravatar_id":"","url":"https://api.github.com/users/leonschoorl","html_url":"https://github.com/leonschoorl","followers_url":"https://api.github.com/users/leonschoorl/followers","following_url":"https://api.github.com/users/leonschoorl/following{/other_user}","gists_url":"https://api.github.com/users/leonschoorl/gists{/gist_id}","starred_url":"https://api.github.com/users/leonschoorl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/leonschoorl/subscriptions","organizations_url":"https://api.github.com/users/leonschoorl/orgs","repos_url":"https://api.github.com/users/leonschoorl/repos","events_url":"https://api.github.com/users/leonschoorl/events{/privacy}","received_events_url":"https://api.github.com/users/leonschoorl/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2018-10-31T16:43:46Z","updated_at":"2018-12-05T10:18:53Z","closed_at":"2018-12-05T10:18:53Z","author_association":"CONTRIBUTOR","body":"HiddenClockReset gets specialized away by GHC?\r\n\r\nThanks to @lonetech for finding [this](https://gist.github.com/lonetech/4745ed78488abd7dd25246334a3cc868)\r\n\r\nMinimized testcase\r\n```haskell\r\nimport Clash.Prelude\r\n\r\ndelayEn\r\n  :: HiddenClockReset System Source Asynchronous\r\n  => Signal System () -> Signal System (Unsigned 4)\r\ndelayEn _ = queue\r\n  where\r\n    queue = register 0 queue\r\n-- Both INLINE and NOINLINE makes the problem go away:\r\n-- {-# NOINLINE delayEn #-}\r\n-- {-# INLINE delayEn #-}\r\n\r\ntopEntity\r\n  :: HiddenClockReset System Source Asynchronous\r\n  => Signal System ()\r\n  -> Signal System (Unsigned 4)\r\ntopEntity = delayEn\r\n\r\n-- This sort of simulation helper causes compiler confusion\r\nsimThunc = simulate topEntity []\r\n```\r\n\r\nClash crashes with:\r\n```\r\n    Clash error call:\r\n    Clash.Netlist(623): mkDcApplication undefined for: (Clock \"system\" 10000 Gated,Name {nameSort = User, nameOcc = Clash.Signal.Internal.GatedClock8214565720323809944, ...}, ...)\r\n```\r\n\r\nSo clash is trying to generate an expression of type `Clock System Gated` by using the data constructor `GatedClock` and fails.\r\nWhich is to be expected, you can't generate clocks that way.\r\n\r\nBut we're only using `Source` clocks here, so where is this GatedClock coming from?\r\n\r\nUsing `-ddump-simpl -ddump-spec` we see that GHC generates a two specialized version of `delayEn`:\r\n  * the first one for use in `topEntity`, specialized on the the hidden arguments from the `HiddenClockReset`\r\n  * the second one used in `simThunc`, this one gets specialized on the (unsafe coerced) GatedClock from the definition of [simulate]\r\n\r\nBut both have the same signature:\r\n```haskell\r\n$sdelayEn_sdWV :: Signal System () -> Signal System (Unsigned 4)\r\n$sdelayEn_sdWV\r\n  = \\ _ [Occ=Dead] ->\r\n...\r\n              ((GHC.Classes.$p1(%,%)\r\n                  @ (HiddenClock System 'Source)\r\n                  @ (HiddenReset System 'Asynchronous)\r\n                  $d(%,%)_sdWU)\r\n               `cast` (GHC.Classes.N:IP[0] <\"clk\">_N <Clock System 'Source>_N\r\n                       :: (?clk::Clock System 'Source :: Constraint)\r\n                          ~R# (Clock System 'Source :: *)))\r\n...\r\n\r\n\r\nMain.delayEn_$sdelayEn :: Signal System () -> Signal System (Unsigned 4)\r\nMain.delayEn_$sdelayEn\r\n  = \\ _ [Occ=Dead] ->\r\n...\r\n              (Clash.Signal.sample5\r\n               `cast` ((Clock <System>_N (UnsafeCo nominal 'Gated 'Source))_R\r\n                       :: (Clock System 'Gated :: *) ~R# (Clock System 'Source :: *)))\r\n...\r\n\r\n```\r\n\r\nAnd then GHC seems to decide these specializations can be used interchangeably, forgets the first one and uses the second one (with the unsafe clocks) everywhere.\r\n\r\nPutting a `NOINLINE` on the simulate function fixes the problem.\r\n\r\nBut I'm wondering whether GHC should be allowed to do this or if it's our fault for using `unsafeCoerce` (incorrectly?)\r\n\r\n[simulate]: (https://github.com/clash-lang/clash-compiler/blob/e9430fab21ec246756f1bb238268872e083f5193/clash-prelude/src/Clash/Signal.hs#L682-L689)"}}
{"actor":{"display_login":"christiaanb"}}