Open gergoerdi opened 3 years ago
I have uploaded a version that at least doesn't contain a full Space Invaders machine :)
https://github.com/gergoerdi/clash-intel8080/tree/clash-issue-1536
Build with stack build && stack runhaskell -- build.hs
.
Compiles to Verilog: https://github.com/gergoerdi/clash-intel8080/tree/57c1939bd6967ef9a851055a9288a2596436036b Fails: https://github.com/gergoerdi/clash-intel8080/tree/84b6e5fe5417e8f64190e2329a7267ab080f88f8
A few pointers for people looking to solve this bug:
origInl
. A thing with a unique of 3
heavily implies it was generated by Clash. It'd be interesting to see how it's used.reduceBindersCleanup
is tested in isolation here: https://github.com/clash-lang/clash-compiler/blob/b0a239e1a6b0e0d0f7cf63a0c85f2c1448a0a13e/clash-lib/tests/Clash/Tests/Normalize/Transformations.hs. If there's nothing obvious wrong in step (1), try to put the entirety of the graph in origInl
in there (like t1337a
) and start reducing it until it doesn't fail.@gergoerdi This might just be a frivolous error message. If you're in a hurry you might want to try removing it entirely from reduceBindersCleanup
and see if your design still works.
I tried removing the error message, but then I get this:
../src/top.hs:20:1: error:
Clash.Netlist(385): Not in normal form: Var-application with Type arguments:
<prefixName>"$p2(%,%)"
c$sel[3][LocalId]
@(GHC.Maybe.Maybe[3674937295934324792]
(Data.Either.Either[3674937295934324904]
Hardware.Intel8080.Microcode.Addressing[8214565720324144085]
Hardware.Intel8080.Microcode.Addressing[8214565720324144085]))
The source location of the error is not exact, only indicative, as it is acquired
after optimizations. The actual location of the error can be in a function that is
inlined. To prevent inlining of those functions, annotate them with a NOINLINE pragma.
|
20 | topEntity = withEnableGen board
| ^^^^^^^^^
It seems I can work around this issue by doing some Template Haskell to force microcode to normal form before hitting Clash.
@gergoerdi When I try to run
stack build && stack runhaskell -- build.hs
I get:
<no location info>: error: can't find file: build.hs
Did you forget to add build.hs
? :)
Are you on the right branch? It should be clash-issue-1536
. I can see the file right there.
facepalm
I removed the repo because I forgot --recursive
(and didn't want to bother looking up how to clone submodules after the fact), and then forgot to checkout the branch again.
As of e6738d181690c22e931779f47ad058eb50c266f4 I managed to trigger this again:
<no location info>: error:
Clash error call:
Internal error: 'reduceBindersCleanup' encountered a variable reference that was
neither in 'doneInl', 'origInl', or in the transformation's in scope set. Unique
was: '6989586621679302210'.
CallStack (from HasCallStack):
error, called at src/Clash/Normalize/Transformations.hs:2664:11 in clash-lib-1.3.0-BtaSQT9Z6y828nb9DyhjHh:Clash.Normalize.Transformations
reduceBindersCleanup, called at src/Clash/Normalize/Transformations.hs:2625:30 in clash-lib-1.3.0-BtaSQT9Z6y828nb9DyhjHh:Clash.Normalize.Transformations
inlineBndrsCleanup, called at src/Clash/Normalize/Transformations.hs:2510:19 in clash-lib-1.3.0-BtaSQT9Z6y828nb9DyhjHh:Clash.Normalize.Transformations
inlineCleanup, called at src/Clash/Normalize/Strategy.hs:57:53 in clash-lib-1.3.0-BtaSQT9Z6y828nb9DyhjHh:Clash.Normalize.Strategy
Full code is at https://github.com/gergoerdi/clash-issue-1536/tree/5a4f39db790eb1bac425e1d3883e27a353df6d42 just run build.sh
after checkout
I will keep pushing to https://github.com/gergoerdi/clash-issue-1536/tree/clash-issue-1536 as I try to simplify my code.
Hrmpf, I managed to simplify my code to the point where I am getting "Clash.Normalize
(192): Clash can only normalize monomorphic functions, but this is polymorphic" instead, so I guess I'll have to completely rethink my approach in https://github.com/gergoerdi/retroclash-lib/blob/05b6f8cdaebfb77edb4db4a422b0817feeaca770/src/RetroClash/Memory.hs anyway...
Adding -fclash-debug DebugSilent
shows that it goes wrong earlier: ANF introduces free variables. However, that again is a proxy for a failure upstream. That is, I'm seeing that the expression on which ANF fails is:
<no location info>: error:
Clash error call:
Clash.Rewrite.Util(249): Error when applying rewrite ANF to:
λ(r1[8286623314361845567] :: Clash.Signal.Internal.Signal[8214565720323789676]
"System"
(GHC.Maybe.Maybe[3674937295934324792]
(Clash.Sized.Internal.Unsigned.Unsigned[8214565720323789711]
16))) ->
case Data.Dependent.Map.unionWithKey
where I expect that that unionWithKey
should have been compile-time evaluated. (The ANF transform happens after compile-time evaluation). The problem is that ANF only works correctly when certain invariants hold, but those invariants aren't checked (adding that check would make the common case expensive, so we don't do it), and those invariants only don't hold when something is bugged earlier in the compile process.
Anyhow... investigating further why the compile-time evaluation of that unionWithKey
isn't being evaluated at compile-time.
Well ideally the whole of this memoryMap
stuff should be evaluated at compile-time. In the meantime, in desperation I started rewriting the whole shebang using Template Haskell but it is looking way worse...
Mmm... if that Data.Dependent.Map.unionWithKey
is this one: https://hackage.haskell.org/package/dependent-map-0.4.0.0/docs/src/Data.Dependent.Map.html#unionWithKey
Than I think what is going on is that there is no unfolding / Core expression corresponding to that unionWithKey
, as it is recursive, and so Clash cannot evaluate at compile time. Top-level recursive bindings never get an unfolding, unless the library is build with -fexpose-all-unfoldings
. @gergoerdi Are you building all your dependencies with -fexpose-all-unfoldings
? Is that possbible with stack
?
With cabal
you could add the following to your cabal.project
file:
package *
ghc-options: -fexpose-all-unfoldings
That still won't get you all the unfoldings for all of your dependencies though, libraries that are bundled with GHC, such as base
still won't have unfoldings for things like the recursive Data.List.map
.
Hmm that's a very good point -- I build all my own libraries with -fexpose-all-unfoldings
but I don't know how to pass that to all eternal dependencies as well. Let me look around.
@gergoerdi Are you building all your dependencies with -fexpose-all-unfoldings? Is that possbible with stack?
There is an option, but the details aren't pretty. I am now trying to compile with the flag set on only the dependent-map
package, and, well, all I can say so far is that it hasn't errored out yet... it's been running for 5+ minutes, so let's wait and see.
BTW, what exactly does the 'inlining limit' mean? I am getting error messages from Clash that an inlining limit of e.g. 100 isn't enough to deal with the unionWithKey
stuff, but I am building tiny DMap
s with 4 entry...
It limits how often a (global) function f
is inlined in the subject of the expression case (f ...) of
. The inlining currently only happens when f
returns a data type that cannot be represented by a bundle of wires. It is limited because Clash cannot determine beforehand whether inlining will ever terminate.
So does that mean I am somehow getting a 100-deep recursive chain of calls to go
in unionWithKey
? That would be very surprising for a 4-element DMap
.
Yes, that’s what it means. The eager parallel reduction is not necessarily efficient. Actually, Clash doesn’t have a well defined compile-time semantics at all. The underlying rewrite mechanism is only guaranteed to be able to translate a Haskell program to a circuit when all transformations are applied exhaustively; the implementation has picked a somewhat ad-hoc set of tree traversals to achieve this exhaustive rewrite.
What this means is that Clash is/can be very bad at compile-time evaluation, especially partial evaluation (where the expression under evaluation has variables). That is why @alex-mckenna is hard at work to create a proper partial evaluator. But the problem is very non-trivial to solve, so an industrial-strength implementation is still far away.
Soooo does this mean this is hopeless, and I should start thinking seriously about the TH based approach?
Is there some debug flag I could pass to clash
to see what exactly (if anything) it is doing while it is spinning at 100% CPU with -fexpose-all-unfoldings
on dependent-map
and a large enough -fclash-inline-limit
?
You could try -fclash-debug DebugName
to see a list of (applied) transformations. More verbose options exist but aren't guaranteed to producte readable output :^).
My hunch is that the problem is going to be this recursive piece of code:
{-# INLINE memoryMap #-}
memoryMap
:: Signal dom (Maybe addr)
-> Signal dom (Maybe dat)
-> (forall s. Addressing s dom dat addr a)
-> (Signal dom (Maybe dat), a)
memoryMap addr wr body = (join <$> firstIn read, x)
where
(x, (read, conns)) = evalRWS (unAddressing body) (fanInMaybe addr, wr, conns) 0
Here, we tie the knot on conns
which is an essential part of the code: we need to know the address line going into a memory element when we create that memory element, but we need memory element handles so we can connect address lines to them.
You could try
-fclash-debug DebugName
to see a list of (applied) transformations.
It ends up cycling on the following:
caseCase {205290}
caseCase {205291}
applicationPropagation {205292}
bindOrLiftNonRep {205293}
caseCon {205294}
applicationPropagation {205295}
bindOrLiftNonRep {205296}
bindOrLiftNonRep {205297}
caseCase {205298}
applicationPropagation {205299}
bindOrLiftNonRep {205300}
caseCon {205301}
caseCase {205302}
caseCase {205303}
applicationPropagation {205304}
caseCase {205305}
applicationPropagation {205306}
caseCase {205307}
applicationPropagation {205308}
bindOrLiftNonRep {205309}
Does it terminate if you don't use a knot-tied defined conns
? But something like:
{-# INLINE memoryMap #-}
memoryMap
:: Signal dom (Maybe addr)
-> Signal dom (Maybe dat)
-> (forall s. Addressing s dom dat addr a)
-> _
-> (Signal dom (Maybe dat), a)
memoryMap addr wr body bogusConns = (join <$> firstIn read, x)
where
(x, (read, _conns)) = evalRWS (unAddressing body) (fanInMaybe addr, wr, bogusConns) 0
The only bogusConns
I can easily come up with is mempty
, so I tried that, and that causes Clash to synthesize in 40 seconds. Of course, the resulting circuit isn't what I want :)
There's not some singleton singleBogusCon
implementation where you can float the singleBogusCon
value all the way up? So that we can at least get some additional structure.
While trying to minimize https://github.com/clash-lang/clash-compiler/issues/1611, I managed to trigger this bug again, with a fairly small & self-contained way of reproducing it!
https://github.com/gergoerdi/clash-issue-1611/tree/clash-issue-1536
<no location info>: error:
Clash error call:
Internal error: 'reduceBindersCleanup' encountered a variable reference that was
neither in 'doneInl', 'origInl', or in the transformation's in scope set. Unique
was: '6989586621679258275'.
CallStack (from HasCallStack):
error, called at src/Clash/Normalize/Transformations.hs:2664:11 in clash-lib-1.3.0-BtaSQT9Z6y828nb9DyhjHh:Clash.Normalize.Transformations
reduceBindersCleanup, called at src/Clash/Normalize/Transformations.hs:2625:30 in clash-lib-1.3.0-BtaSQT9Z6y828nb9DyhjHh:Clash.Normalize.Transformations
inlineBndrsCleanup, called at src/Clash/Normalize/Transformations.hs:2510:19 in clash-lib-1.3.0-BtaSQT9Z6y828nb9DyhjHh:Clash.Normalize.Transformations
inlineCleanup, called at src/Clash/Normalize/Strategy.hs:57:53 in clash-lib-1.3.0-BtaSQT9Z6y828nb9DyhjHh:Clash.Normalize.Strategy
There's not some
singleton singleBogusCon
implementation where you can float thesingleBogusCon
value all the way up? So that we can at least get some additional structure.
OK I have now done that (see this commit), but I'm not sure what we're supposed to see here. Compiling with an inliner limit of 1000, it doesn't diverge (so that's an improvement compared to the knot-tying version), but it still complains about not enough inlinings:
Clash.Normalize.Transformations(432): InlineNonRep: c$Hardware.SpaceInvaders.mainBoard_go_go[660417] already inlined 1000 times in:c$Hardware.SpaceInvaders.mainBoard_go[358191]
Type of the subject is: Data.Dependent.Map.Internal.DMap[8214565720324068564]
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766])
(RetroClash.Memory.Component[8214565720324068547]
(GHC.Types.Any[3674937295934325098]
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766]))
(GHC.Types.Any[3674937295934325098]
(GHC.Types.Any[3674937295934325098]
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766]))))
(RetroClash.Memory.FanIn[8214565720324068556] "Dom25")
Function c$Hardware.SpaceInvaders.mainBoard_go[358191] will not reach a normal form, and compilation might fail.
Run with '-fclash-inline-limit=N' to increase the inlining limit to N.
Would it help if I put in the effort to make a single-module version of this (similar to https://github.com/clash-lang/clash-compiler/issues/1611#issuecomment-740572475)? Or it's not going to change anything, because even if the non-knotted version could be synthesized, the current evaluator has no chance of normalizing the knotted one?
Right now, I don't see any reason why the compiler should not be able to normalize the knotted one, aside from:
Here's a managable (<100 lines!) standalone version of this code:
{-# LANGUAGE DerivingStrategies, GeneralizedNewtypeDeriving #-}
{-# LANGUAGE RankNTypes #-}
module Board where
import Clash.Prelude
import Data.Maybe
import Control.Monad
import Control.Monad.RWS
import Data.Kind
import Data.Dependent.Map as DMap
import Data.GADT.Compare
import Type.Reflection
data Component s (addr :: Type) = Component (TypeRep addr) Int
instance GEq (Component s) where
geq (Component a _) (Component b _) = geq a b
instance GCompare (Component s) where
gcompare (Component a _) (Component b _) = gcompare a b
newtype FanIn dom a = FanIn{ getFanIn :: Signal dom `Ap` First a }
deriving newtype (Semigroup, Monoid)
newtype AddrMap s dom = AddrMap{ addrMap :: DMap (Component s) (FanIn dom) }
deriving newtype (Monoid)
instance Semigroup (AddrMap s dom) where
AddrMap map1 <> AddrMap map2 = AddrMap $ unionWithKey (const mappend) map1 map2
newtype Addressing s dom dat addr a = Addressing
{ unAddressing :: RWS
(FanIn dom addr, AddrMap s dom)
(FanIn dom (Maybe dat), AddrMap s dom)
Int
a
}
deriving newtype (Functor, Applicative, Monad)
memoryMap
:: Signal dom (Maybe addr)
-> Signal dom (Maybe dat)
-> (forall s. Addressing s dom dat addr a)
-> (Signal dom (Maybe dat), a)
memoryMap addr wr body = (join <$> firstIn read, x)
where
(x, (read, conns)) = evalRWS (unAddressing body) (fanInMaybe addr, conns) 0
readWrite_
:: (HiddenClockResetEnable dom, Typeable addr')
=> (Signal dom (Maybe addr') -> Signal dom (Maybe dat))
-> Addressing s dom dat addr (Component s addr')
readWrite_ mkComponent = Addressing $ do
component <- Component typeRep <$> get <* modify succ
(_, addrs) <- ask
let addr = firstIn . fromMaybe mempty $ DMap.lookup component (addrMap addrs)
read = mkComponent addr
tell (fanIn read, mempty)
return component
ram0
:: (HiddenClockResetEnable dom, 1 <= n, NFDataX dat, Num dat)
=> SNat n
-> Addressing s dom dat addr (Component s (Index n))
ram0 size@SNat = readWrite_ $ \addr ->
fmap Just $ blockRam1 ClearOnReset size 0 (fromMaybe 0 <$> addr) (pure Nothing)
connect
:: Component s addr
-> Addressing s dom dat addr ()
connect component@(Component _ i) = Addressing $ do
(addr, _) <- ask
tell (mempty, AddrMap $ DMap.singleton component addr)
firstIn :: FanIn dom a -> Signal dom (Maybe a)
firstIn = fmap getFirst . getAp . getFanIn
fanInMaybe :: Signal dom (Maybe a) -> FanIn dom a
fanInMaybe = FanIn . Ap . fmap First
fanIn :: Signal dom a -> FanIn dom a
fanIn = fanInMaybe . fmap pure
topEntity
:: Clock System
-> Reset System
-> Signal System (Maybe (Index 0x0400))
-> Signal System (Maybe (Unsigned 8))
-> (Signal System (Maybe (Unsigned 8)), ())
topEntity clk rst addr wr = withClockResetEnable clk rst enableGen $ memoryMap addr wr $ do
ram <- ram0 (SNat @0x0400)
connect ram
Crucially, this version still uses knot-tying in memoryMap
, which according to @christiaanb 's latest comment, should be fine. Compared to #1611, I don't see anything in Clash's output about TypeRep
:
Clash.Normalize.Transformations(430): InlineNonRep: c$Board.memoryMap_r1[3867] already inlined 100 times in:Board.memoryMap[3860]
Type of the subject is: GHC.Tuple.(,)[3746994889972252676]
(Board.FanIn[8214565720323973518]
"System"
(Clash.Sized.Internal.Index.Index[8214565720323789680]
1024))
(Board.AddrMap[8214565720323973515]
(GHC.Types.Any[3674937295934325098]
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766]))
"System")
Function Board.memoryMap[3860] will not reach a normal form, and compilation might fail.
Run with '-fclash-inline-limit=N' to increase the inlining limit to N.
Clash.Normalize.Transformations(430): InlineNonRep: c$Board.memoryMap_r1[3867] already inlined 100 times in:Board.memoryMap[3860]
Type of the subject is: GHC.Tuple.(,)[3746994889972252676]
(Board.FanIn[8214565720323973518]
"System"
(Clash.Sized.Internal.Index.Index[8214565720323789680]
1024))
(Board.AddrMap[8214565720323973515]
(GHC.Types.Any[3674937295934325098]
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766]))
"System")
Function Board.memoryMap[3860] will not reach a normal form, and compilation might fail.
Run with '-fclash-inline-limit=N' to increase the inlining limit to N.
Clash.Normalize.Transformations(430): InlineNonRep: c$Board.memoryMap_r1[3867] already inlined 100 times in:Board.memoryMap[3860]
Type of the subject is: GHC.Tuple.(,)[3746994889972252676]
(Board.FanIn[8214565720323973518]
"System"
(Clash.Sized.Internal.Index.Index[8214565720323789680]
1024))
(Board.AddrMap[8214565720323973515]
(GHC.Types.Any[3674937295934325098]
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766]))
"System")
Function Board.memoryMap[3860] will not reach a normal form, and compilation might fail.
Run with '-fclash-inline-limit=N' to increase the inlining limit to N.
Clash.Normalize.Transformations(430): InlineNonRep: c$Board.memoryMap_r1[3867] already inlined 100 times in:Board.memoryMap[3860]
Type of the subject is: GHC.Tuple.(,)[3746994889972252676]
(Board.FanIn[8214565720323973518]
"System"
(Clash.Sized.Internal.Index.Index[8214565720323789680]
1024))
(Board.AddrMap[8214565720323973515]
(GHC.Types.Any[3674937295934325098]
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766]))
"System")
Function Board.memoryMap[3860] will not reach a normal form, and compilation might fail.
Run with '-fclash-inline-limit=N' to increase the inlining limit to N.
src/Board.hs:91:1: error:
Hit specialisation limit 20 on function `c$Board.topEntity_go[14209]'.
The function `c$Board.topEntity_go[14209] :: Data.Dependent.Map.Internal.DMap[8214565720323790117]
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766])
(Board.Component[8214565720323973521]
(GHC.Types.Any[3674937295934325098]
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766])))
(Board.FanIn[8214565720323973518] "System")
-> Clash.Signal.Internal.Signal[8214565720323789647]
"System"
(Data.Monoid.First[8214565720323789960]
(Clash.Sized.Internal.Index.Index[8214565720323789680]
1024))' is most likely recursive, and looks like it is being indefinitely specialized on a growing argument.
Body of `c$Board.topEntity_go[14209] :: Data.Dependent.Map.Internal.DMap[8214565720323790117]
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766])
(Board.Component[8214565720323973521]
(GHC.Types.Any[3674937295934325098]
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766])))
(Board.FanIn[8214565720323973518] "System")
-> Clash.Signal.Internal.Signal[8214565720323789647]
"System"
(Data.Monoid.First[8214565720323789960]
(Clash.Sized.Internal.Index.Index[8214565720323789680]
1024))':
(Λs[6989586621679212316] ->
λ(ds2[6989586621679214230] :: Data.Dependent.Map.Internal.DMap[8214565720323790117]
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766])
(Board.Component[8214565720323973521]
s[6989586621679212316])
(Board.FanIn[8214565720323973518]
"System")) ->
case ds2[6989586621679214230][LocalId] of
Data.Dependent.Map.Internal.Tip[8214565720323790142]
->
Board.$fMonoidFanIn_z[8214565720323996529][GlobalId]
@(Clash.Sized.Internal.Index.Index[8214565720323789680]
1024)
@"System"
Data.Dependent.Map.Internal.Bin[8214565720323790143] v1[6989586621679214234]
(dt[6989586621679214235] :: GHC.Prim.Int#[3674937295934324764])
(kx[6989586621679214236] :: Board.Component[8214565720323973521]
s[6989586621679212316]
v1[6989586621679214234])
(x[6989586621679214237] :: Board.FanIn[8214565720323973518]
"System"
v1[6989586621679214234])
(l[6989586621679214238] :: Data.Dependent.Map.Internal.DMap[8214565720323790117]
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766])
(Board.Component[8214565720323973521]
s[6989586621679212316])
(Board.FanIn[8214565720323973518]
"System"))
(r[6989586621679214239] :: Data.Dependent.Map.Internal.DMap[8214565720323790117]
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766])
(Board.Component[8214565720323973521]
s[6989586621679212316])
(Board.FanIn[8214565720323973518]
"System")) ->
case kx[6989586621679214236][LocalId] of
Board.Component[8214565720323973522]
(b1[6989586621679200383] :: Data.Typeable.Internal.TypeRep[3674937295934325110]
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766])
v1[6989586621679214234])
(ds3[7205759403793008602] :: GHC.Types.Int[3674937295934324766]) ->
case Data.GADT.Internal.$fGComparekTypeRep_$cgcompare[8214565720323973567][GlobalId]
@(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766])
@(Clash.Sized.Internal.Index.Index[8214565720323789680]
1024)
@v1[6989586621679214234]
c$Board.topEntity_$dTypeable[2817][GlobalId]
b1[6989586621679200383][LocalId] of
Data.GADT.Internal.GLT[8214565720323790214] ->
c$Board.topEntity_go[3045][GlobalId]
@s[6989586621679212316]
l[6989586621679214238][LocalId]
Data.GADT.Internal.GEQ[8214565720323790216]
(co[6989586621679214248] :: GHC.Prim.~#[3674937295934324842]
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766])
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766])
v1[6989586621679214234]
(Clash.Sized.Internal.Index.Index[8214565720323789680]
1024)) ->
x[6989586621679214237][LocalId]
Data.GADT.Internal.GGT[8214565720323790217] ->
c$Board.topEntity_go[3045][GlobalId]
@s[6989586621679212316]
r[6989586621679214239][LocalId])
@(GHC.Types.Any[3674937295934325098]
(GHC.Prim.TYPE[3674937295934324912]
GHC.Types.LiftedRep[3891110078048108766]))
Argument (in position: 0) that triggered termination:
<prefixName>"memoryMap_r1"
letrec
$dIP[8286623314361928287] :: GHC.Classes.IP[3602879701896396848]
"enable"
(Clash.Signal.Internal.Enable[8214565720323789617]
"System")
= <prefixName>"memoryMap_ds"
<prefixName>"topEntity_ds"
<prefixName>"ram0"
letrec
$d(%,%)[8286623314361928111] :: GHC.Classes.(%,%)[7710162562058289156]
(GHC.Classes.IP[3602879701896396848]
"enable"
(Clash.Signal.Internal.Enable[8214565720323789617]
"System"))
(Clash.Signal.Internal.KnownDomain[8214565720323789624]
"System")
= <prefixName>"$p3(%,,%)"
GHC.Classes.C:(%,%)[8214565720323984092]
@(GHC.Classes.IP[3602879701896396848]
"enable"
(Clash.Signal.Internal.Enable[8214565720323789617]
"System"))
@(Clash.Signal.Internal.KnownDomain[8214565720323789624]
"System")
<prefixName>"enableGen"
(Clash.Signal.Internal.Enable[8214565720323854607]
@"System"
<prefixName>"enableGen1"
GHC.Types.True[3891110078048108589])
(Clash.Signal.Internal.C:KnownDomain[8214565720323856279]
@"System"
(GHC.CString.unpackCString# "System")
(Clash.Signal.Internal.SDomainConfiguration[8214565720323789637]
@"System"
@(Clash.Signal.Internal.DomainConfiguration[8214565720323789606]
"System"
10000
Clash.Signal.Internal.Rising[8214565720323789601]
Clash.Signal.Internal.Asynchronous[8214565720323789628]
Clash.Signal.Internal.Defined[8214565720323789619]
Clash.Signal.Internal.ActiveHigh[8214565720323789631])
@10000
@Clash.Signal.Internal.Rising[8214565720323789601]
@Clash.Signal.Internal.Asynchronous[8214565720323789628]
@Clash.Signal.Internal.Defined[8214565720323789619]
@Clash.Signal.Internal.ActiveHigh[8214565720323789631]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.DomainConfiguration[8214565720323789605]
Clash.Signal.Internal.DomainConfiguration[8214565720323789605]
(Clash.Signal.Internal.DomainConfiguration[8214565720323789606]
"System"
10000
Clash.Signal.Internal.Rising[8214565720323789601]
Clash.Signal.Internal.Asynchronous[8214565720323789628]
Clash.Signal.Internal.Defined[8214565720323789619]
Clash.Signal.Internal.ActiveHigh[8214565720323789631])
(Clash.Signal.Internal.DomainConfiguration[8214565720323789606]
"System"
10000
Clash.Signal.Internal.Rising[8214565720323789601]
Clash.Signal.Internal.Asynchronous[8214565720323789628]
Clash.Signal.Internal.Defined[8214565720323789619]
Clash.Signal.Internal.ActiveHigh[8214565720323789631])))
(Clash.Promoted.Symbol.SSymbol @"System"
(GHC.CString.unpackCString# "System"))
(Clash.Promoted.Nat.SNat[8214565720323789569]
@10000
10000)
(Clash.Signal.Internal.SRising[8214565720323789635]
@Clash.Signal.Internal.Rising[8214565720323789601]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.ActiveEdge[8214565720323789599]
Clash.Signal.Internal.ActiveEdge[8214565720323789599]
Clash.Signal.Internal.Rising[8214565720323789601]
Clash.Signal.Internal.Rising[8214565720323789601])))
(Clash.Signal.Internal.SAsynchronous[8214565720323789642]
@Clash.Signal.Internal.Asynchronous[8214565720323789628]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.ResetKind[8214565720323789627]
Clash.Signal.Internal.ResetKind[8214565720323789627]
Clash.Signal.Internal.Asynchronous[8214565720323789628]
Clash.Signal.Internal.Asynchronous[8214565720323789628])))
(Clash.Signal.Internal.SDefined[8214565720323789639]
@Clash.Signal.Internal.Defined[8214565720323789619]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.InitBehavior[8214565720323789618]
Clash.Signal.Internal.InitBehavior[8214565720323789618]
Clash.Signal.Internal.Defined[8214565720323789619]
Clash.Signal.Internal.Defined[8214565720323789619])))
(Clash.Signal.Internal.SActiveHigh[8214565720323789645]
@Clash.Signal.Internal.ActiveHigh[8214565720323789631]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.ResetPolarity[8214565720323789630]
Clash.Signal.Internal.ResetPolarity[8214565720323789630]
Clash.Signal.Internal.ActiveHigh[8214565720323789631]
Clash.Signal.Internal.ActiveHigh[8214565720323789631])))))
in <prefixName>"$p1(%,%)"
case $d(%,%)[8286623314361928111][LocalId] of
GHC.Classes.C:(%,%)[8214565720323984092]
(c$sel[3] :: GHC.Classes.IP[3602879701896396848]
"enable"
(Clash.Signal.Internal.Enable[8214565720323789617]
"System"))
(c$wild[2] :: Clash.Signal.Internal.KnownDomain[8214565720323789624]
"System") ->
c$sel[3][LocalId]
in letrec
a'[6989586621679217849] :: Board.FanIn[8214565720323973518]
"System"
(GHC.Maybe.Maybe[3674937295934324792]
(Clash.Sized.Internal.Unsigned.Unsigned[8214565720323789682]
8))
= <prefixName>"$fMonoidFirst_$c<>"
letrec
ds4[8214565720324007144] :: Data.Monoid.First[8214565720323789960]
(GHC.Maybe.Maybe[3674937295934324792]
(Clash.Sized.Internal.Unsigned.Unsigned[8214565720323789682]
8))
= <prefixName>"fanIn2"
letrec
eta1[4755801206503243959] :: GHC.Maybe.Maybe[3674937295934324792]
(GHC.Maybe.Maybe[3674937295934324792]
(Clash.Sized.Internal.Unsigned.Unsigned[8214565720323789682]
8))
= GHC.Maybe.Just[3891110078048108571]
@(GHC.Maybe.Maybe[3674937295934324792]
(Clash.Sized.Internal.Unsigned.Unsigned[8214565720323789682]
8))
(letrec
addr1[6989586621679204334] :: Clash.Signal.Internal.Signal[8214565720323789647]
"System"
(GHC.Maybe.Maybe[3674937295934324792]
(Clash.Sized.Internal.Index.Index[8214565720323789680]
1024))
= <prefixName>"$fGeneric1First2"
letrec
x[8214565720324007947] :: Data.Monoid.First[8214565720323789960]
(Clash.Sized.Internal.Index.Index[8214565720323789680]
1024)
= c$Board.topEntity_go[14245][GlobalId]
addr1[3858][LocalId]
clk[6989586621679204400][LocalId]
rst[6989586621679204401][LocalId]
in x[8214565720324007947][LocalId]
in GHC.Maybe.Just[3891110078048108571]
@(Clash.Sized.Internal.Unsigned.Unsigned[8214565720323789682]
8)
(Clash.Explicit.BlockRam.blockRam1[3856][GlobalId]
<prefixName>"topEntity_ds"
<prefixName>"ram0"
<prefixName>"$p2(%,%)"
<prefixName>"topEntity_ds"
<prefixName>"ram0"
<prefixName>"$p1(%,,%)"
(Clash.Signal.Internal.C:KnownDomain[8214565720323856279]
@"System"
(GHC.CString.unpackCString# "System")
(Clash.Signal.Internal.SDomainConfiguration[8214565720323789637]
@"System"
@(Clash.Signal.Internal.DomainConfiguration[8214565720323789606]
"System"
10000
Clash.Signal.Internal.Rising[8214565720323789601]
Clash.Signal.Internal.Asynchronous[8214565720323789628]
Clash.Signal.Internal.Defined[8214565720323789619]
Clash.Signal.Internal.ActiveHigh[8214565720323789631])
@10000
@Clash.Signal.Internal.Rising[8214565720323789601]
@Clash.Signal.Internal.Asynchronous[8214565720323789628]
@Clash.Signal.Internal.Defined[8214565720323789619]
@Clash.Signal.Internal.ActiveHigh[8214565720323789631]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.DomainConfiguration[8214565720323789605]
Clash.Signal.Internal.DomainConfiguration[8214565720323789605]
(Clash.Signal.Internal.DomainConfiguration[8214565720323789606]
"System"
10000
Clash.Signal.Internal.Rising[8214565720323789601]
Clash.Signal.Internal.Asynchronous[8214565720323789628]
Clash.Signal.Internal.Defined[8214565720323789619]
Clash.Signal.Internal.ActiveHigh[8214565720323789631])
(Clash.Signal.Internal.DomainConfiguration[8214565720323789606]
"System"
10000
Clash.Signal.Internal.Rising[8214565720323789601]
Clash.Signal.Internal.Asynchronous[8214565720323789628]
Clash.Signal.Internal.Defined[8214565720323789619]
Clash.Signal.Internal.ActiveHigh[8214565720323789631])))
(Clash.Promoted.Symbol.SSymbol @"System"
(GHC.CString.unpackCString# "System"))
(Clash.Promoted.Nat.SNat[8214565720323789569]
@10000
10000)
(Clash.Signal.Internal.SRising[8214565720323789635]
@Clash.Signal.Internal.Rising[8214565720323789601]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.ActiveEdge[8214565720323789599]
Clash.Signal.Internal.ActiveEdge[8214565720323789599]
Clash.Signal.Internal.Rising[8214565720323789601]
Clash.Signal.Internal.Rising[8214565720323789601])))
(Clash.Signal.Internal.SAsynchronous[8214565720323789642]
@Clash.Signal.Internal.Asynchronous[8214565720323789628]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.ResetKind[8214565720323789627]
Clash.Signal.Internal.ResetKind[8214565720323789627]
Clash.Signal.Internal.Asynchronous[8214565720323789628]
Clash.Signal.Internal.Asynchronous[8214565720323789628])))
(Clash.Signal.Internal.SDefined[8214565720323789639]
@Clash.Signal.Internal.Defined[8214565720323789619]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.InitBehavior[8214565720323789618]
Clash.Signal.Internal.InitBehavior[8214565720323789618]
Clash.Signal.Internal.Defined[8214565720323789619]
Clash.Signal.Internal.Defined[8214565720323789619])))
(Clash.Signal.Internal.SActiveHigh[8214565720323789645]
@Clash.Signal.Internal.ActiveHigh[8214565720323789631]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.ResetPolarity[8214565720323789630]
Clash.Signal.Internal.ResetPolarity[8214565720323789630]
Clash.Signal.Internal.ActiveHigh[8214565720323789631]
Clash.Signal.Internal.ActiveHigh[8214565720323789631])))))
GHC.Stack.Types.EmptyCallStack[8214565720323979068]
(GHC.Types.Eq#[3891110078048108574]
@GHC.Types.Bool[3674937295934324744]
@(GHC.TypeNats.<=?[3674937295934325074] 1 1024)
@GHC.Types.True[3891110078048108589]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
GHC.Types.Bool[3674937295934324744]
GHC.Types.Bool[3674937295934324744]
(GHC.TypeNats.<=?[3674937295934325074] 1 1024)
GHC.Types.True[3891110078048108589])))
<prefixName>"topEntity_ds"
<prefixName>"ram0"
<prefixName>"$p1(%,%)"
<prefixName>"topEntity_ds"
<prefixName>"ram0"
<prefixName>"$p1(%,,%)"
clk[6989586621679204400][LocalId]
<prefixName>"topEntity_ds"
<prefixName>"ram0"
<prefixName>"$p1(%,%)"
<prefixName>"$p2(%,,%)"
rst[6989586621679204401][LocalId]
$dIP[8286623314361928287][LocalId]
(Clash.Explicit.BlockRam.ClearOnReset[8214565720323789560]
@GHC.Types.True[3891110078048108589]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
GHC.Types.Bool[3674937295934324744]
GHC.Types.Bool[3674937295934324744]
GHC.Types.True[3891110078048108589]
GHC.Types.True[3891110078048108589])))
(Clash.Promoted.Nat.SNat[8214565720323789569]
@1024
1024)
<prefixName>"fromInteger"
(<prefixName>"$s$fNumUnsigned"
<prefixName>"$s$fNumUnsigned6"
Clash.Sized.Internal.Unsigned.fromInteger# @8 8
0)
(case addr1[6989586621679204334][LocalId] of
GHC.Maybe.Nothing[3891110078048108568] ->
Clash.Sized.Internal.Index.fromInteger# @1024
1024
0
GHC.Maybe.Just[3891110078048108571]
(v[6989586621679214219] :: Clash.Sized.Internal.Index.Index[8214565720323789680]
1024) ->
v[6989586621679214219][LocalId])
(GHC.Maybe.Nothing[3891110078048108568]
@(GHC.Tuple.(,)[3746994889972252676]
(Clash.Sized.Internal.Index.Index[8214565720323789680]
1024)
(Clash.Sized.Internal.Unsigned.Unsigned[8214565720323789682]
8)))))
in eta1[4755801206503243959][LocalId]
in case ds4[8214565720324007144][LocalId] of
GHC.Maybe.Nothing[3891110078048108568] ->
<prefixName>"$fMonoidFanIn_z"
GHC.Maybe.Nothing[3891110078048108568]
@(GHC.Maybe.Maybe[3674937295934324792]
(Clash.Sized.Internal.Unsigned.Unsigned[8214565720323789682]
8))
GHC.Maybe.Just[3891110078048108571]
(ipv[8214565720324006969] :: GHC.Maybe.Maybe[3674937295934324792]
(Clash.Sized.Internal.Unsigned.Unsigned[8214565720323789682]
8)) ->
ds4[8214565720324007144][LocalId]
in Board.$fApplicativeAddressing2[14224][GlobalId]
addr1[3858][LocalId]
Run with '-fclash-spec-limit=N' to increase the specialisation limit to N.
The source location of the error is not exact, only indicative, as it is acquired
after optimizations. The actual location of the error can be in a function that is
inlined. To prevent inlining of those functions, annotate them with a NOINLINE pragma.
|
91 | topEntity clk rst addr wr = withClockResetEnable clk rst enableGen $ memoryMap addr wr $ do
| ^^^^^^^^^
However, similar to #1611, if I remove the part that actually uses TypeRep
s, i.e. if I change topEntity
to
topEntity clk rst addr wr = withClockResetEnable clk rst enableGen $ memoryMap addr wr $ do
() <- return ()
return ()
then it synthesizes without complaints. So now I don't know if this is the same problem as #1611 or not...
Using the Clash instrumentation from https://github.com/clash-lang/clash-compiler/issues/1611#issuecomment-743139000, I see the following set of unfoldable definitions:
--
Control.Monad.Trans.RWS.Lazy.$tcRWST1
Data.Monoid.$fSemigroupAp_$cstimes
Data.Monoid.$fSemigroupFirst1
Data.Monoid.$tcAp1
Data.OldList.intercalate_$spoly_go
Data.OldList.prependToAll
Data.Semigroup.Internal.$wstimesDefault
Data.Sequence.Internal.$fFunctorSeq_$cfmap
Data.Sequence.Internal.$fIsListSeq_mkTree
Data.Sequence.Internal.$w$slookupTree
Data.Sequence.Internal.$wupdate
Data.Typeable.Internal.$tcAppOrCon1
Data.Typeable.Internal.$wmkTrCon
Data.Typeable.Internal.eqTypeRep
Data.Typeable.Internal.fpTYPELiftedRep
Data.Typeable.Internal.typeRepTyCon
Foreign.Storable.$fStorableFingerprint_$s$wpeekW64
Foreign.Storable.$fStorableFingerprint_$s$wpokeW64
GHC.Base.++
GHC.Base.++_$s++
GHC.Base.map
GHC.CString.unpackAppendCString#
GHC.Fingerprint.fingerprintString_go
GHC.Integer.Type.czeroBigNat
GHC.Integer.Type.nullBigNat
GHC.Integer.Type.oneBigNat
GHC.Integer.Type.zeroBigNat
GHC.List.$wlenAcc
GHC.List.reverse1
GHC.List.splitAt_$s$wsplitAt'
GHC.Prim.addWordC#
GHC.Prim.byteArrayContents#
GHC.Prim.catch#
GHC.Prim.getSizeofMutableByteArray#
GHC.Prim.indexWordArray#
GHC.Prim.newAlignedPinnedByteArray#
GHC.Prim.newByteArray#
GHC.Prim.newPinnedByteArray#
GHC.Prim.plusAddr#
GHC.Prim.proxy#
GHC.Prim.raise#
GHC.Prim.raiseIO#
GHC.Prim.readWord8OffAddr#
GHC.Prim.readWordArray#
GHC.Prim.realWorld#
GHC.Prim.reallyUnsafePtrEquality#
GHC.Prim.resizeMutableByteArray#
GHC.Prim.seq#
GHC.Prim.setByteArray#
GHC.Prim.shrinkMutableByteArray#
GHC.Prim.sizeofByteArray#
GHC.Prim.timesWord2#
GHC.Prim.touch#
GHC.Prim.unsafeFreezeByteArray#
GHC.Prim.void#
GHC.Prim.writeWord8OffAddr#
GHC.Prim.writeWordArray#
GHC.Show.$fShowInteger_jprintb
GHC.Show.$witos'
GHC.Show.$wjblock'
GHC.Show.$wjsplitf
GHC.Show.$wshowWord
GHC.Show.showLitString
GHC.Stack.Types.getCallStack
GHC.Types.$tc'AddrRep1
GHC.Types.$tcTYPE1
Most of these are base
definitions so they aren't recompiled with -fexpose-all-unfoldings
. The RWS one is surprising to me, because I have asked stack
to recompile mtl
and transformers
with the flag. @christiaanb are you seeing a similar list?
And as for the Typeable
stuff, of course if the whole of memoryMap
is compiled away, there is no HDL-time stuff remaining that uses them. So there shouldn't be a need for blackboxes implementing the Typeable
methods, I think.
Conjecture: things from transformers
are likely included because it is a boot library. I believe this is why things from integer-gmp
are included as well. Most of these seem alright to be missing from the primitive evaluation to me, although some I can't immediately figure out what they are (other than some worker)
@gergoerdi Yeah, I'm seeing a similar list. And you're correct, we should not have blackboxes for the Typeable
methods, but we do need their Core
representations in order to do any compile-time evaluation.
Edit: wrt Control.Monad.Trans.RWS.Lazy.$tcRWST1
perhaps stack
is refusing to rebuild transformer
because as @alex-mckenna suggests, it's a boot library. That's my conjecture as I have the exact same unfolding missing and I didn't rebuild transformers
.
So dependent-map
(and specifically, its use of Typeable
) is the only blocking problem here? I will try to think about a non-dependent-map
-using solution then.
It's hard to determine whether there is an additional problem on top of dependent-map
s use of Typeable
.
I got rid of using dependent-map
by using unsafeCoerce
internally (yuck!). First, it looks promising, because taking the smallest example and pushing it through Clash works:
{-# LANGUAGE DerivingStrategies, GeneralizedNewtypeDeriving #-}
{-# LANGUAGE RankNTypes #-}
module Board where
import Clash.Prelude
import Data.Maybe
import Control.Monad
import Control.Monad.RWS
import Unsafe.Coerce
import Data.Map as Map
newtype Component s addr = Component Int
deriving newtype (Eq, Ord)
newtype FanIn dom a = FanIn{ getFanIn :: Signal dom `Ap` First a }
deriving newtype (Semigroup, Monoid)
newtype AddrMap s dom = AddrMap{ addrMap :: Map Int (FanIn dom ()) }
deriving newtype (Monoid)
instance Semigroup (AddrMap s dom) where
AddrMap map1 <> AddrMap map2 = AddrMap $ unionWithKey (const mappend) map1 map2
newtype Addressing s dom dat addr a = Addressing
{ unAddressing :: RWS
(FanIn dom addr, AddrMap s dom)
(FanIn dom (Maybe dat), AddrMap s dom)
Int
a
}
deriving newtype (Functor, Applicative, Monad)
memoryMap
:: Signal dom (Maybe addr)
-> (forall s. Addressing s dom dat addr a)
-> (Signal dom (Maybe dat), a)
memoryMap addr body = (join <$> firstIn read, x)
where
(x, (read, conns)) = evalRWS (unAddressing body) (fanInMaybe addr, conns) 0
readWrite_
:: (HiddenClockResetEnable dom)
=> (Signal dom (Maybe addr') -> Signal dom (Maybe dat))
-> Addressing s dom dat addr (Component s addr')
readWrite_ mkComponent = Addressing $ do
component@(Component i) <- Component <$> get <* modify succ
(_, addrs) <- ask
let addr = firstIn . fromMaybe mempty $ Map.lookup i (addrMap addrs)
read = mkComponent $ unsafeCoerce addr
tell (fanIn read, mempty)
return component
ram0
:: (HiddenClockResetEnable dom, 1 <= n, NFDataX dat, Num dat)
=> SNat n
-> Addressing s dom dat addr (Component s (Index n))
ram0 size@SNat = readWrite_ $ \addr ->
fmap Just $ blockRam1 ClearOnReset size 0 (fromMaybe 0 <$> addr) (pure Nothing)
connect
:: Component s addr
-> Addressing s dom dat addr ()
connect component@(Component i) = Addressing $ do
(addr, _) <- ask
tell (mempty, AddrMap $ Map.singleton i $ unsafeCoerce addr)
firstIn :: FanIn dom a -> Signal dom (Maybe a)
firstIn = fmap getFirst . getAp . getFanIn
fanInMaybe :: Signal dom (Maybe a) -> FanIn dom a
fanInMaybe = FanIn . Ap . fmap First
fanIn :: Signal dom a -> FanIn dom a
fanIn = fanInMaybe . fmap pure
topEntity
:: Clock System
-> Reset System
-> Signal System (Maybe (Index 0x0400))
-> (Signal System (Maybe (Unsigned 8)), ())
topEntity clk rst addr = withClockResetEnable clk rst enableGen $ memoryMap addr $ do
ram <- ram0 (SNat @0x0400)
connect ram
But then if I add matchAddr
back so that topEntity
can get a bit more complex, we are back to square one, except this time it's containers
's Data.Map.lookup
screwing things up:
matchAddr
:: (addr -> Maybe addr')
-> Addressing s dom dat addr' a
-> Addressing s dom dat addr a
matchAddr match body = Addressing $ rws $ \(addr, addrs) s ->
let addr' = fanInMaybe . fmap (match =<<) . firstIn $ addr
in runRWS (unAddressing body) (addr', addrs) s
from
:: forall addr' s dom dat addr a. (Integral addr, Ord addr, Integral addr', Bounded addr')
=> addr
-> Addressing s dom dat addr' a
-> Addressing s dom dat addr a
from base = matchAddr $ \addr -> do
guard $ addr >= base
let offset = addr - base
guard $ offset <= lim
return $ fromIntegral offset
where
lim = fromIntegral (maxBound :: addr')
topEntity
:: Clock System
-> Reset System
-> Signal System (Maybe (Index 0x0800))
-> (Signal System (Maybe (Unsigned 8)), ())
topEntity clk rst addr = withClockResetEnable clk rst enableGen $ memoryMap addr $ do
ram <- ram0 (SNat @0x0400)
from 0x0000 $ connect ram
from 0x0400 $ connect ram
Clash.Normalize.Transformations(432): InlineNonRep: c$Board.$slookup_go13_wild[12457728] already inlined 200 times in:Board.$slookup_go13[12025728]
Type of the subject is: Data.Map.Internal.Map[8214565720323790163]
GHC.Types.Int[3674937295934324766]
(Clash.Signal.Internal.Signal[8214565720323789649]
"System"
(GHC.Maybe.Maybe[3674937295934324792]
GHC.Tuple.()[3746994889972252672]))
So it seems this will never quite work out, unless we can get the boot libraries compiled with -fexpose-all-unfoldings
(and probably also -fno-worker-wrapper
)... Would this approach work for that, to decouple Clash from GHC and have Clash compile everything on its own?
I think we want the “fat interface files” described here: https://gitlab.haskell.org/ghc/ghc/-/issues/10871 Which apparently is something ghcide wants as well.
Also to check whether fat interface files would be a solution is to import Data.Map.Internal
and copy/paste the definitions of the functions that you’re using from Data.Map
Also to check whether fat interface files would be a solution is to import
Data.Map.Internal
and copy/paste the definitions of the functions that you’re using fromData.Map
Yeah I had the same idea in the meantime, I'm working on this right now.
Well, it's pretty much the same with an included copy of Data.Map
, just with different non-unfoldable functions remaining:
--
Control.Monad.Trans.RWS.Lazy.$tcRWST1
Data.Data.$c(,)
Data.Data.$fData[]_$cgfoldl
Data.Data.$fData[]_$cgmapM
Data.Data.$fData[]_$cgmapQ
Data.Data.$fData[]_$cgmapQi
Data.Data.$fData[]_$cgmapQl
Data.Data.$fData[]_$cgmapQr
Data.Data.$fData[]_$cgmapT
Data.Data.$fData[]_$cgunfold
Data.Data.$w$cgmapMo11
Data.Data.$w$cgmapMp16
Data.Data.consConstr
Data.Data.listDataType
Data.Data.nilConstr
Data.Functor.Classes.$fEq1NonEmpty_$cliftEq1
Data.Functor.Classes.$fOrd1NonEmpty_$cliftCompare1
Data.Functor.Classes.$fRead1(,)_$cliftReadList
Data.Monoid.$fSemigroupAp_$cstimes
Data.Monoid.$fSemigroupFirst1
Data.Monoid.$tcAp1
Data.OldList.intercalate_$spoly_go
Data.OldList.prependToAll
Data.Semigroup.Internal.$wstimesDefault
Data.Sequence.Internal.$fFunctorSeq_$cfmap
Data.Sequence.Internal.$fIsListSeq_mkTree
Data.Sequence.Internal.$w$slookupTree
Data.Sequence.Internal.$wupdate
Data.Typeable.Internal.$wmkTrCon
Data.Typeable.Internal.eqTypeRep
Data.Typeable.Internal.fpTYPELiftedRep
Foreign.Storable.$fStorableFingerprint_$s$wpeekW64
Foreign.Storable.$fStorableFingerprint_$s$wpokeW64
GHC.Base.++
GHC.Base.++_$s++
GHC.Base.eqString
GHC.Base.map
GHC.CString.unpackAppendCString#
GHC.Classes.$fEq[]_$c==
GHC.Classes.$fOrd[]_$ccompare
GHC.Integer.Type.czeroBigNat
GHC.Integer.Type.nullBigNat
GHC.Integer.Type.oneBigNat
GHC.Integer.Type.zeroBigNat
GHC.List.$wlenAcc
GHC.List.reverse1
GHC.List.splitAt_$s$wsplitAt'
GHC.Prim.addWordC#
GHC.Prim.byteArrayContents#
GHC.Prim.catch#
GHC.Prim.getSizeofMutableByteArray#
GHC.Prim.indexWordArray#
GHC.Prim.newAlignedPinnedByteArray#
GHC.Prim.newByteArray#
GHC.Prim.newPinnedByteArray#
GHC.Prim.plusAddr#
GHC.Prim.proxy#
GHC.Prim.raise#
GHC.Prim.raiseIO#
GHC.Prim.readWord8OffAddr#
GHC.Prim.readWordArray#
GHC.Prim.realWorld#
GHC.Prim.reallyUnsafePtrEquality#
GHC.Prim.resizeMutableByteArray#
GHC.Prim.seq#
GHC.Prim.setByteArray#
GHC.Prim.shrinkMutableByteArray#
GHC.Prim.sizeofByteArray#
GHC.Prim.timesWord2#
GHC.Prim.touch#
GHC.Prim.unsafeFreezeByteArray#
GHC.Prim.void#
GHC.Prim.writeWord8OffAddr#
GHC.Prim.writeWordArray#
GHC.Read.list
GHC.Real.$wf1
GHC.Show.$fShow(,)_$sgo1
GHC.Show.$fShowInteger_jprintb
GHC.Show.$witos'
GHC.Show.$wjblock'
GHC.Show.$wjsplitf
GHC.Show.showLitString
GHC.Stack.Types.getCallStack
GHC.Types.$tc'AddrRep1
GHC.Types.$tcTYPE1
Text.ParserCombinators.ReadP.$fAlternativeP_$c<|>
Text.ParserCombinators.ReadP.gather_gath
Text.ParserCombinators.ReadP.run
Text.ParserCombinators.ReadP.skipSpaces2
Text.Read.Lex.expect2
_INTERNAL_.{__pkg_ccall base-4.13.0.0 Addr#
_INTERNAL_.{__pkg_ccall base-4.13.0.0 Int#
_INTERNAL_.{__pkg_ccall integer-gmp-1.0.2.0 ByteArray#
_INTERNAL_.{__pkg_ccall integer-gmp-1.0.2.0 forall s.
Eventualy, the specializer chokes on the (copied, and thus unfoldable) version of Data.Map.lookup
:
Hit specialisation limit 100 on function `c$Board.topEntity_go[11136]'.
The function `c$Board.topEntity_go[11136] :: GHC.Types.Int[3674937295934324766]
-> Containers.Data.Map.Internal.Map[8214565720323896040]
GHC.Types.Int[3674937295934324766]
(Board.FanIn[8214565720324216431]
"System"
GHC.Tuple.()[3746994889972252672])
-> Clash.Signal.Internal.Signal[8214565720324039903]
"System"
(Data.Monoid.First[8214565720323804916]
GHC.Tuple.()[3746994889972252672])' is most likely recursive, and looks like it is being indefinitely specialized on a growing argument.
Body of `c$Board.topEntity_go[11136] :: GHC.Types.Int[3674937295934324766]
-> Containers.Data.Map.Internal.Map[8214565720323896040]
GHC.Types.Int[3674937295934324766]
(Board.FanIn[8214565720324216431]
"System"
GHC.Tuple.()[3746994889972252672])
-> Clash.Signal.Internal.Signal[8214565720324039903]
"System"
(Data.Monoid.First[8214565720323804916]
GHC.Tuple.()[3746994889972252672])':
λ(ds2[7205759403792923820] :: GHC.Types.Int[3674937295934324766]) ->
λ(ds3[7205759403792923821] :: Containers.Data.Map.Internal.Map[8214565720323896040]
GHC.Types.Int[3674937295934324766]
(Board.FanIn[8214565720324216431]
"System"
GHC.Tuple.()[3746994889972252672])) ->
letrec
ds4[6341068275337788595] :: GHC.Types.Int[3674937295934324766]
= ds2[7205759403792923820][LocalId]
in case ds4[6341068275337788595][LocalId] of
GHC.Types.I#[3891110078048108562]
(ipv[8286623314362161582] :: GHC.Prim.Int#[3674937295934324764]) ->
case ds3[7205759403792923821][LocalId] of
Containers.Data.Map.Internal.Bin[8214565720323896041]
(ipv1[8286623314361847773] :: GHC.Types.Int[3674937295934324766])
(ipv2[8286623314361847774] :: GHC.Types.Int[3674937295934324766])
(ipv3[8286623314361847775] :: Board.FanIn[8214565720324216431]
"System"
GHC.Tuple.()[3746994889972252672])
(ipv4[8286623314361847776] :: Containers.Data.Map.Internal.Map[8214565720323896040]
GHC.Types.Int[3674937295934324766]
(Board.FanIn[8214565720324216431]
"System"
GHC.Tuple.()[3746994889972252672]))
(ipv5[8286623314361847777] :: Containers.Data.Map.Internal.Map[8214565720323896040]
GHC.Types.Int[3674937295934324766]
(Board.FanIn[8214565720324216431]
"System"
GHC.Tuple.()[3746994889972252672])) ->
case ipv2[8286623314361847774][LocalId] of
GHC.Types.I#[3891110078048108562]
(y#[6989586621679066384] :: GHC.Prim.Int#[3674937295934324764]) ->
case GHC.Prim.<#
ipv[8286623314362161582][LocalId]
y#[6989586621679066384][LocalId] of
_ ->
case GHC.Prim.==#
ipv[8286623314362161582][LocalId]
y#[6989586621679066384][LocalId] of
_ ->
c$Board.topEntity_go[11136][GlobalId]
ds4[6341068275337788595][LocalId]
ipv5[8286623314361847777][LocalId]
1 ->
ipv3[8286623314361847775][LocalId]
1 ->
c$Board.topEntity_go[11136][GlobalId]
ds4[6341068275337788595][LocalId]
ipv4[8286623314361847776][LocalId]
Containers.Data.Map.Internal.Tip[8214565720323896042]
->
Board.$fMonoidFanIn1[8214565720324228805][GlobalId]
@GHC.Tuple.()[3746994889972252672]
@"System"
Argument (in position: 1) that triggered termination:
<prefixName>"memoryMap_r1"
letrec
$dIP2[8286623314362162379] :: GHC.Classes.IP[3602879701896396848]
"enable"
(Clash.Signal.Internal.Enable[8214565720324039873]
"System")
= <prefixName>"memoryMap_ds"
<prefixName>"topEntity_ds"
<prefixName>"ram0"
letrec
$d(%,%)1[8286623314362161981] :: GHC.Classes.(%,%)[7710162562058289156]
(GHC.Classes.IP[3602879701896396848]
"enable"
(Clash.Signal.Internal.Enable[8214565720324039873]
"System"))
(Clash.Signal.Internal.KnownDomain[8214565720324039880]
"System")
= <prefixName>"$p3(%,,%)"
GHC.Classes.C:(%,%)[8214565720323792659]
@(GHC.Classes.IP[3602879701896396848]
"enable"
(Clash.Signal.Internal.Enable[8214565720324039873]
"System"))
@(Clash.Signal.Internal.KnownDomain[8214565720324039880]
"System")
<prefixName>"enableGen"
(Clash.Signal.Internal.Enable[8214565720324098780]
@"System"
<prefixName>"enableGen1"
GHC.Types.True[3891110078048108589])
(Clash.Signal.Internal.C:KnownDomain[8214565720324100457]
@"System"
(GHC.CString.unpackCString# "System")
(Clash.Signal.Internal.SDomainConfiguration[8214565720324039893]
@"System"
@(Clash.Signal.Internal.DomainConfiguration[8214565720324039862]
"System"
10000
Clash.Signal.Internal.Rising[8214565720324039857]
Clash.Signal.Internal.Asynchronous[8214565720324039884]
Clash.Signal.Internal.Defined[8214565720324039875]
Clash.Signal.Internal.ActiveHigh[8214565720324039887])
@10000
@Clash.Signal.Internal.Rising[8214565720324039857]
@Clash.Signal.Internal.Asynchronous[8214565720324039884]
@Clash.Signal.Internal.Defined[8214565720324039875]
@Clash.Signal.Internal.ActiveHigh[8214565720324039887]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.DomainConfiguration[8214565720324039861]
Clash.Signal.Internal.DomainConfiguration[8214565720324039861]
(Clash.Signal.Internal.DomainConfiguration[8214565720324039862]
"System"
10000
Clash.Signal.Internal.Rising[8214565720324039857]
Clash.Signal.Internal.Asynchronous[8214565720324039884]
Clash.Signal.Internal.Defined[8214565720324039875]
Clash.Signal.Internal.ActiveHigh[8214565720324039887])
(Clash.Signal.Internal.DomainConfiguration[8214565720324039862]
"System"
10000
Clash.Signal.Internal.Rising[8214565720324039857]
Clash.Signal.Internal.Asynchronous[8214565720324039884]
Clash.Signal.Internal.Defined[8214565720324039875]
Clash.Signal.Internal.ActiveHigh[8214565720324039887])))
(Clash.Promoted.Symbol.SSymbol @"System"
(GHC.CString.unpackCString# "System"))
(Clash.Promoted.Nat.SNat[8214565720324039825]
@10000
10000)
(Clash.Signal.Internal.SRising[8214565720324039891]
@Clash.Signal.Internal.Rising[8214565720324039857]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.ActiveEdge[8214565720324039855]
Clash.Signal.Internal.ActiveEdge[8214565720324039855]
Clash.Signal.Internal.Rising[8214565720324039857]
Clash.Signal.Internal.Rising[8214565720324039857])))
(Clash.Signal.Internal.SAsynchronous[8214565720324039898]
@Clash.Signal.Internal.Asynchronous[8214565720324039884]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.ResetKind[8214565720324039883]
Clash.Signal.Internal.ResetKind[8214565720324039883]
Clash.Signal.Internal.Asynchronous[8214565720324039884]
Clash.Signal.Internal.Asynchronous[8214565720324039884])))
(Clash.Signal.Internal.SDefined[8214565720324039895]
@Clash.Signal.Internal.Defined[8214565720324039875]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.InitBehavior[8214565720324039874]
Clash.Signal.Internal.InitBehavior[8214565720324039874]
Clash.Signal.Internal.Defined[8214565720324039875]
Clash.Signal.Internal.Defined[8214565720324039875])))
(Clash.Signal.Internal.SActiveHigh[8214565720324039901]
@Clash.Signal.Internal.ActiveHigh[8214565720324039887]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.ResetPolarity[8214565720324039886]
Clash.Signal.Internal.ResetPolarity[8214565720324039886]
Clash.Signal.Internal.ActiveHigh[8214565720324039887]
Clash.Signal.Internal.ActiveHigh[8214565720324039887])))))
in <prefixName>"$p1(%,%)"
case $d(%,%)1[8286623314362161981][LocalId] of
GHC.Classes.C:(%,%)[8214565720323792659]
(c$sel[3] :: GHC.Classes.IP[3602879701896396848]
"enable"
(Clash.Signal.Internal.Enable[8214565720324039873]
"System"))
(c$wild[2] :: Clash.Signal.Internal.KnownDomain[8214565720324039880]
"System") ->
c$sel[3][LocalId]
in letrec
a'[6989586621679449989] :: Board.FanIn[8214565720324216431]
"System"
(GHC.Maybe.Maybe[3674937295934324792]
(Clash.Sized.Internal.Unsigned.Unsigned[8214565720324039938]
8))
= <prefixName>"$fMonoidFirst_$c<>"
letrec
ds4[8214565720324239755] :: Data.Monoid.First[8214565720323804916]
(GHC.Maybe.Maybe[3674937295934324792]
(Clash.Sized.Internal.Unsigned.Unsigned[8214565720324039938]
8))
= <prefixName>"fanIn2"
letrec
eta[4755801206503244181] :: GHC.Maybe.Maybe[3674937295934324792]
(GHC.Maybe.Maybe[3674937295934324792]
(Clash.Sized.Internal.Unsigned.Unsigned[8214565720324039938]
8))
= GHC.Maybe.Just[3891110078048108571]
@(GHC.Maybe.Maybe[3674937295934324792]
(Clash.Sized.Internal.Unsigned.Unsigned[8214565720324039938]
8))
(letrec
addr1[6989586621679445142] :: Clash.Signal.Internal.Signal[8214565720324039903]
"System"
(GHC.Maybe.Maybe[3674937295934324792]
(Clash.Sized.Internal.Index.Index[8214565720324039936]
1024))
= <prefixName>"$fGeneric1First2"
letrec
x[8214565720324239622] :: Data.Monoid.First[8214565720323804916]
GHC.Tuple.()[3746994889972252672]
= c$Board.topEntity_go[24275126][GlobalId]
(GHC.Types.I# 0)
addr1[25363][LocalId]
clk[6989586621679444994][LocalId]
rst[6989586621679444995][LocalId]
in x[8214565720324239622][LocalId]
in GHC.Maybe.Just[3891110078048108571]
@(Clash.Sized.Internal.Unsigned.Unsigned[8214565720324039938]
8)
(Clash.Explicit.BlockRam.blockRam1[25360][GlobalId]
<prefixName>"topEntity_ds"
<prefixName>"ram0"
<prefixName>"$p2(%,%)"
<prefixName>"topEntity_ds"
<prefixName>"ram0"
<prefixName>"$p1(%,,%)"
(Clash.Signal.Internal.C:KnownDomain[8214565720324100457]
@"System"
(GHC.CString.unpackCString# "System")
(Clash.Signal.Internal.SDomainConfiguration[8214565720324039893]
@"System"
@(Clash.Signal.Internal.DomainConfiguration[8214565720324039862]
"System"
10000
Clash.Signal.Internal.Rising[8214565720324039857]
Clash.Signal.Internal.Asynchronous[8214565720324039884]
Clash.Signal.Internal.Defined[8214565720324039875]
Clash.Signal.Internal.ActiveHigh[8214565720324039887])
@10000
@Clash.Signal.Internal.Rising[8214565720324039857]
@Clash.Signal.Internal.Asynchronous[8214565720324039884]
@Clash.Signal.Internal.Defined[8214565720324039875]
@Clash.Signal.Internal.ActiveHigh[8214565720324039887]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.DomainConfiguration[8214565720324039861]
Clash.Signal.Internal.DomainConfiguration[8214565720324039861]
(Clash.Signal.Internal.DomainConfiguration[8214565720324039862]
"System"
10000
Clash.Signal.Internal.Rising[8214565720324039857]
Clash.Signal.Internal.Asynchronous[8214565720324039884]
Clash.Signal.Internal.Defined[8214565720324039875]
Clash.Signal.Internal.ActiveHigh[8214565720324039887])
(Clash.Signal.Internal.DomainConfiguration[8214565720324039862]
"System"
10000
Clash.Signal.Internal.Rising[8214565720324039857]
Clash.Signal.Internal.Asynchronous[8214565720324039884]
Clash.Signal.Internal.Defined[8214565720324039875]
Clash.Signal.Internal.ActiveHigh[8214565720324039887])))
(Clash.Promoted.Symbol.SSymbol @"System"
(GHC.CString.unpackCString# "System"))
(Clash.Promoted.Nat.SNat[8214565720324039825]
@10000
10000)
(Clash.Signal.Internal.SRising[8214565720324039891]
@Clash.Signal.Internal.Rising[8214565720324039857]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.ActiveEdge[8214565720324039855]
Clash.Signal.Internal.ActiveEdge[8214565720324039855]
Clash.Signal.Internal.Rising[8214565720324039857]
Clash.Signal.Internal.Rising[8214565720324039857])))
(Clash.Signal.Internal.SAsynchronous[8214565720324039898]
@Clash.Signal.Internal.Asynchronous[8214565720324039884]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.ResetKind[8214565720324039883]
Clash.Signal.Internal.ResetKind[8214565720324039883]
Clash.Signal.Internal.Asynchronous[8214565720324039884]
Clash.Signal.Internal.Asynchronous[8214565720324039884])))
(Clash.Signal.Internal.SDefined[8214565720324039895]
@Clash.Signal.Internal.Defined[8214565720324039875]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.InitBehavior[8214565720324039874]
Clash.Signal.Internal.InitBehavior[8214565720324039874]
Clash.Signal.Internal.Defined[8214565720324039875]
Clash.Signal.Internal.Defined[8214565720324039875])))
(Clash.Signal.Internal.SActiveHigh[8214565720324039901]
@Clash.Signal.Internal.ActiveHigh[8214565720324039887]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
Clash.Signal.Internal.ResetPolarity[8214565720324039886]
Clash.Signal.Internal.ResetPolarity[8214565720324039886]
Clash.Signal.Internal.ActiveHigh[8214565720324039887]
Clash.Signal.Internal.ActiveHigh[8214565720324039887])))))
GHC.Stack.Types.EmptyCallStack[8214565720323830335]
(GHC.Types.Eq#[3891110078048108574]
@GHC.Types.Bool[3674937295934324744]
@(GHC.TypeNats.<=?[3674937295934325074] 1 1024)
@GHC.Types.True[3891110078048108589]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
GHC.Types.Bool[3674937295934324744]
GHC.Types.Bool[3674937295934324744]
(GHC.TypeNats.<=?[3674937295934325074] 1 1024)
GHC.Types.True[3891110078048108589])))
<prefixName>"topEntity_ds"
<prefixName>"ram0"
<prefixName>"$p1(%,%)"
<prefixName>"topEntity_ds"
<prefixName>"ram0"
<prefixName>"$p1(%,,%)"
clk[6989586621679444994][LocalId]
<prefixName>"topEntity_ds"
<prefixName>"ram0"
<prefixName>"$p1(%,%)"
<prefixName>"$p2(%,,%)"
rst[6989586621679444995][LocalId]
$dIP2[8286623314362162379][LocalId]
(Clash.Explicit.BlockRam.ClearOnReset[8214565720324039816]
@GHC.Types.True[3891110078048108589]
(_CO_
@(GHC.Prim.~#[3674937295934324842]
GHC.Types.Bool[3674937295934324744]
GHC.Types.Bool[3674937295934324744]
GHC.Types.True[3891110078048108589]
GHC.Types.True[3891110078048108589])))
(Clash.Promoted.Nat.SNat[8214565720324039825]
@1024
1024)
<prefixName>"fromInteger"
(<prefixName>"$s$fNumUnsigned"
<prefixName>"$s$fNumUnsigned6"
Clash.Sized.Internal.Unsigned.fromInteger# @8 8
0)
(case addr1[6989586621679445142][LocalId] of
GHC.Maybe.Nothing[3891110078048108568] ->
Clash.Sized.Internal.Index.fromInteger# @1024
1024
0
GHC.Maybe.Just[3891110078048108571]
(v[6989586621679448424] :: Clash.Sized.Internal.Index.Index[8214565720324039936]
1024) ->
v[6989586621679448424][LocalId])
(GHC.Maybe.Nothing[3891110078048108568]
@(GHC.Tuple.(,)[3746994889972252676]
(Clash.Sized.Internal.Index.Index[8214565720324039936]
1024)
(Clash.Sized.Internal.Unsigned.Unsigned[8214565720324039938]
8)))))
in eta[4755801206503244181][LocalId]
in case ds4[8214565720324239755][LocalId] of
GHC.Maybe.Nothing[3891110078048108568] ->
<prefixName>"$fMonoidFanIn1"
GHC.Maybe.Nothing[3891110078048108568]
@(GHC.Maybe.Maybe[3674937295934324792]
(Clash.Sized.Internal.Unsigned.Unsigned[8214565720324039938]
8))
GHC.Maybe.Just[3891110078048108571]
(ipv[8214565720324239762] :: GHC.Maybe.Maybe[3674937295934324792]
(Clash.Sized.Internal.Unsigned.Unsigned[8214565720324039938]
8)) ->
ds4[8214565720324239755][LocalId]
in letrec
addr1[6989586621679445000] :: Board.FanIn[8214565720324216431]
"System"
(Clash.Sized.Internal.Index.Index[8214565720324039936]
1024)
= <prefixName>"topEntity_eta"
<prefixName>"fanIn2"
letrec
eta[4755801206503243795] :: GHC.Maybe.Maybe[3674937295934324792]
(Clash.Sized.Internal.Index.Index[8214565720324039936]
1024)
= <prefixName>"$fMonadMaybe_$c>>="
case <prefixName>"firstIn"
<prefixName>"$fGeneric1First2"
<prefixName>"memoryMap_r1"
<prefixName>"fanInMaybe2"
<prefixName>"fanIn2"
addr1[25363][LocalId] of
GHC.Maybe.Nothing[3891110078048108568] ->
GHC.Maybe.Nothing[3891110078048108568]
@(Clash.Sized.Internal.Index.Index[8214565720324039936]
1024)
GHC.Maybe.Just[3891110078048108571]
(x[8214565720324239227] :: Clash.Sized.Internal.Index.Index[8214565720324039936]
2048) ->
case Clash.Sized.Internal.Index.ge# @2048
x[8214565720324239227][LocalId]
(Clash.Sized.Internal.Index.fromInteger# @2048
2048
0) of
GHC.Types.False[3891110078048108556] ->
GHC.Maybe.Nothing[3891110078048108568]
@(Clash.Sized.Internal.Index.Index[8214565720324039936]
1024)
GHC.Types.True[3891110078048108589] ->
letrec
offset[8286623314362161957] :: Clash.Sized.Internal.Index.Index[8214565720324039936]
2048
= Clash.Sized.Internal.Index.-# @2048
(Clash.Transformations.removedArg
@GHC.Natural.Natural[3674937295934324786])
x[8214565720324239227][LocalId]
(Clash.Sized.Internal.Index.fromInteger# @2048
2048
0)
in case Clash.Sized.Internal.Index.le# @2048
offset[8286623314362161957][LocalId]
<prefixName>"topEntity_ds1"
<prefixName>"from_$sfrom"
(Clash.Sized.Internal.Index.fromInteger# @2048
2048
(Clash.Sized.Internal.Index.toInteger# @1024
(Clash.Sized.Internal.Index.maxBound# @1024
1024))) of
GHC.Types.False[3891110078048108556] ->
GHC.Maybe.Nothing[3891110078048108568]
@(Clash.Sized.Internal.Index.Index[8214565720324039936]
1024)
GHC.Types.True[3891110078048108589] ->
GHC.Maybe.Just[3891110078048108571]
@(Clash.Sized.Internal.Index.Index[8214565720324039936]
1024)
(Clash.Sized.Internal.Index.fromInteger# @1024
1024
(Clash.Sized.Internal.Index.toInteger# @2048
offset[8286623314362161957][LocalId]))
in eta[4755801206503243795][LocalId]
in letrec
addr1[6989586621679445436] :: Board.FanIn[8214565720324216431]
"System"
(Clash.Sized.Internal.Index.Index[8214565720324039936]
1024)
= <prefixName>"topEntity_eta"
<prefixName>"fanIn2"
letrec
eta[4755801206503243789] :: GHC.Maybe.Maybe[3674937295934324792]
(Clash.Sized.Internal.Index.Index[8214565720324039936]
1024)
= <prefixName>"$fMonadMaybe_$c>>="
case <prefixName>"firstIn"
<prefixName>"$fGeneric1First2"
<prefixName>"memoryMap_r1"
<prefixName>"fanInMaybe2"
<prefixName>"fanIn2"
addr1[25363][LocalId] of
GHC.Maybe.Nothing[3891110078048108568] ->
GHC.Maybe.Nothing[3891110078048108568]
@(Clash.Sized.Internal.Index.Index[8214565720324039936]
1024)
GHC.Maybe.Just[3891110078048108571]
(x[8214565720324239227] :: Clash.Sized.Internal.Index.Index[8214565720324039936]
2048) ->
case Clash.Sized.Internal.Index.ge# @2048
x[8214565720324239227][LocalId]
(Clash.Sized.Internal.Index.fromInteger# @2048
2048
1024) of
GHC.Types.False[3891110078048108556] ->
GHC.Maybe.Nothing[3891110078048108568]
@(Clash.Sized.Internal.Index.Index[8214565720324039936]
1024)
GHC.Types.True[3891110078048108589] ->
letrec
offset[8286623314362161957] :: Clash.Sized.Internal.Index.Index[8214565720324039936]
2048
= Clash.Sized.Internal.Index.-# @2048
(Clash.Transformations.removedArg
@GHC.Natural.Natural[3674937295934324786])
x[8214565720324239227][LocalId]
(Clash.Sized.Internal.Index.fromInteger# @2048
2048
1024)
in case Clash.Sized.Internal.Index.le# @2048
offset[8286623314362161957][LocalId]
<prefixName>"topEntity_ds2"
<prefixName>"from_$sfrom"
(Clash.Sized.Internal.Index.fromInteger# @2048
2048
(Clash.Sized.Internal.Index.toInteger# @1024
(Clash.Sized.Internal.Index.maxBound# @1024
1024))) of
GHC.Types.False[3891110078048108556] ->
GHC.Maybe.Nothing[3891110078048108568]
@(Clash.Sized.Internal.Index.Index[8214565720324039936]
1024)
GHC.Types.True[3891110078048108589] ->
GHC.Maybe.Just[3891110078048108571]
@(Clash.Sized.Internal.Index.Index[8214565720324039936]
1024)
(Clash.Sized.Internal.Index.fromInteger# @1024
1024
(Clash.Sized.Internal.Index.toInteger# @2048
offset[8286623314362161957][LocalId]))
in eta[4755801206503243789][LocalId]
in Board.$fApplicativeAddressing_$sunionWithKey[24274924][GlobalId]
addr1[6989586621679445000][LocalId]
addr1[6989586621679445436][LocalId]
Run with '-fclash-spec-limit=N' to increase the specialisation limit to N.
The source location of the error is not exact, only indicative, as it is acquired
after optimizations. The actual location of the error can be in a function that is
inlined. To prevent inlining of those functions, annotate them with a NOINLINE pragma.
|
103 | topEntity clk rst addr = withClockResetEnable clk rst enableGen $ memoryMap addr $ do
| ^^^^^^^^^
This is somewhat better. Specialization is run last in the “eliminate-non-representable-values” phase, indicating the compiler got a whole lot further.
I’ll see whether I can make sense of the Debug output once I have a chance to sit behind a computer.
Thanks for all the effort in helping with the debugging so far!
Thanks for all the effort in helping with the debugging so far!
Well I am completely blocked on this so I am trying everything I can in frustration...
My full code including the copied containers
is at https://github.com/gergoerdi/clash-issue-1536/tree/no-typeable
I've "somewhat" reduced it to:
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DerivingStrategies, GeneralizedNewtypeDeriving #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE MagicHash #-}
module Test where
import Clash.Prelude
import Data.Maybe
import Control.Monad
import Control.Monad.RWS
import Unsafe.Coerce
import GHC.Magic (lazy)
import Data.Foldable as Foldable
import GHC.Exts ( reallyUnsafePtrEquality#, isTrue# )
type Size = Int
data Map k a = Bin {-# UNPACK #-} !Size !k a !(Map k a) !(Map k a)
| Tip
data StrictPair a b = !a :*: !b
infixr 1 :*:
-- | Convert a strict pair to a standard pair.
toPair :: StrictPair a b -> (a, b)
toPair (x :*: y) = (x, y)
{-# INLINE toPair #-}
unions :: (Foldable f, Ord k) => f (Map k a) -> Map k a
unions ts
= Foldable.foldl' union Test.empty ts
singleton :: k -> a -> Map k a
singleton k x = Bin 1 k x Tip Tip
{-# INLINE singleton #-}
lookup :: Ord k => k -> Map k a -> Maybe a
lookup = go
where
go !_ Tip = Nothing
go k (Bin _ kx x l r) = case compare k kx of
LT -> go k l
GT -> go k r
EQ -> Just x
{-# INLINABLE lookup #-}
instance (Ord k) => Monoid (Map k v) where
mempty = Test.empty
mconcat = unions
mappend = union
instance (Ord k) => Semigroup (Map k v) where
(<>) = union
ptrEq :: a -> a -> Bool
-- ptrEq x y = isTrue# (reallyUnsafePtrEquality# x y)
ptrEq _ _ = False
empty :: Map k a
empty = Tip
{-# INLINE empty #-}
insert :: Ord k => k -> a -> Map k a -> Map k a
insert kx0 = go kx0 kx0
where
-- Unlike insertR, we only get sharing here
-- when the inserted value is at the same address
-- as the present value. We try anyway; this condition
-- seems particularly likely to occur in 'union'.
go :: Ord k => k -> k -> a -> Map k a -> Map k a
go orig !_ x Tip = Test.singleton (lazy orig) x
go orig !kx x t@(Bin sz ky y l r) =
case compare kx ky of
LT | l' `ptrEq` l -> t
| otherwise -> balanceL ky y l' r
where !l' = go orig kx x l
GT | r' `ptrEq` r -> t
| otherwise -> balanceR ky y l r'
where !r' = go orig kx x r
EQ | x `ptrEq` y && (lazy orig `seq` (orig `ptrEq` ky)) -> t
| otherwise -> Bin sz (lazy orig) x l r
{-# INLINABLE insert #-}
insertR :: Ord k => k -> a -> Map k a -> Map k a
insertR kx0 = go kx0 kx0
where
go :: Ord k => k -> k -> a -> Map k a -> Map k a
go orig !_ x Tip = Test.singleton (lazy orig) x
go orig !kx x t@(Bin _ ky y l r) =
case compare kx ky of
LT | l' `ptrEq` l -> t
| otherwise -> balanceL ky y l' r
where !l' = go orig kx x l
GT | r' `ptrEq` r -> t
| otherwise -> balanceR ky y l r'
where !r' = go orig kx x r
EQ -> t
{-# INLINABLE insertR #-}
union :: Ord k => Map k a -> Map k a -> Map k a
union t1 Tip = t1
union t1 (Bin _ k x Tip Tip) = insertR k x t1
union (Bin _ k x Tip Tip) t2 = insert k x t2
union Tip t2 = t2
union t1@(Bin _ k1 x1 l1 r1) t2 = case Test.split k1 t2 of
(l2, r2) | l1l2 `ptrEq` l1 && r1r2 `ptrEq` r1 -> t1
| otherwise -> link k1 x1 l1l2 r1r2
where !l1l2 = union l1 l2
!r1r2 = union r1 r2
{-# INLINABLE union #-}
unionWithKey :: Ord k => (k -> a -> a -> a) -> Map k a -> Map k a -> Map k a
unionWithKey _f t1 Tip = t1
unionWithKey f t1 (Bin _ k x Tip Tip) = insertWithKeyR f k x t1
unionWithKey f (Bin _ k x Tip Tip) t2 = insertWithKey f k x t2
unionWithKey _f Tip t2 = t2
unionWithKey f (Bin _ k1 x1 l1 r1) t2 = case splitLookup k1 t2 of
(l2, mb, r2) -> case mb of
Nothing -> link k1 x1 l1l2 r1r2
Just x2 -> link k1 (f k1 x1 x2) l1l2 r1r2
where !l1l2 = unionWithKey f l1 l2
!r1r2 = unionWithKey f r1 r2
{-# INLINABLE unionWithKey #-}
link :: k -> a -> Map k a -> Map k a -> Map k a
link kx x Tip r = insertMin kx x r
link kx x l Tip = insertMax kx x l
link kx x l@(Bin sizeL ky y ly ry) r@(Bin sizeR kz z lz rz)
| delta*sizeL < sizeR = balanceL kz z (link kx x l lz) rz
| delta*sizeR < sizeL = balanceR ky y ly (link kx x ry r)
| otherwise = bin kx x l r
bin :: k -> a -> Map k a -> Map k a -> Map k a
bin k x l r
= Bin (size l + size r + 1) k x l r
{-# INLINE bin #-}
size :: Map k a -> Int
size Tip = 0
size (Bin sz _ _ _ _) = sz
{-# INLINE size #-}
balanceR :: k -> a -> Map k a -> Map k a -> Map k a
balanceR k x l r = case l of
Tip -> case r of
Tip -> Bin 1 k x Tip Tip
(Bin _ _ _ Tip Tip) -> Bin 2 k x Tip r
(Bin _ rk rx Tip rr@(Bin _ _ _ _ _)) -> Bin 3 rk rx (Bin 1 k x Tip Tip) rr
(Bin _ rk rx (Bin _ rlk rlx _ _) Tip) -> Bin 3 rlk rlx (Bin 1 k x Tip Tip) (Bin 1 rk rx Tip Tip)
(Bin rs rk rx rl@(Bin rls rlk rlx rll rlr) rr@(Bin rrs _ _ _ _))
| rls < ratio*rrs -> Bin (1+rs) rk rx (Bin (1+rls) k x Tip rl) rr
| otherwise -> Bin (1+rs) rlk rlx (Bin (1+size rll) k x Tip rll) (Bin (1+rrs+size rlr) rk rx rlr rr)
(Bin ls _ _ _ _) -> case r of
Tip -> Bin (1+ls) k x l Tip
(Bin rs rk rx rl rr)
| rs > delta*ls -> case (rl, rr) of
(Bin rls rlk rlx rll rlr, Bin rrs _ _ _ _)
| rls < ratio*rrs -> Bin (1+ls+rs) rk rx (Bin (1+ls+rls) k x l rl) rr
| otherwise -> Bin (1+ls+rs) rlk rlx (Bin (1+ls+size rll) k x l rll) (Bin (1+rrs+size rlr) rk rx rlr rr)
(_, _) -> error "Failure in Data.Map.balanceR"
| otherwise -> Bin (1+ls+rs) k x l r
{-# NOINLINE balanceR #-}
delta,ratio :: Int
delta = 3
ratio = 2
balanceL :: k -> a -> Map k a -> Map k a -> Map k a
balanceL k x l r = case r of
Tip -> case l of
Tip -> Bin 1 k x Tip Tip
(Bin _ _ _ Tip Tip) -> Bin 2 k x l Tip
(Bin _ lk lx Tip (Bin _ lrk lrx _ _)) -> Bin 3 lrk lrx (Bin 1 lk lx Tip Tip) (Bin 1 k x Tip Tip)
(Bin _ lk lx ll@(Bin _ _ _ _ _) Tip) -> Bin 3 lk lx ll (Bin 1 k x Tip Tip)
(Bin ls lk lx ll@(Bin lls _ _ _ _) lr@(Bin lrs lrk lrx lrl lrr))
| lrs < ratio*lls -> Bin (1+ls) lk lx ll (Bin (1+lrs) k x lr Tip)
| otherwise -> Bin (1+ls) lrk lrx (Bin (1+lls+size lrl) lk lx ll lrl) (Bin (1+size lrr) k x lrr Tip)
(Bin rs _ _ _ _) -> case l of
Tip -> Bin (1+rs) k x Tip r
(Bin ls lk lx ll lr)
| ls > delta*rs -> case (ll, lr) of
(Bin lls _ _ _ _, Bin lrs lrk lrx lrl lrr)
| lrs < ratio*lls -> Bin (1+ls+rs) lk lx ll (Bin (1+rs+lrs) k x lr r)
| otherwise -> Bin (1+ls+rs) lrk lrx (Bin (1+lls+size lrl) lk lx ll lrl) (Bin (1+rs+size lrr) k x lrr r)
(_, _) -> error "Failure in Data.Map.balanceL"
| otherwise -> Bin (1+ls+rs) k x l r
{-# NOINLINE balanceL #-}
insertMax,insertMin :: k -> a -> Map k a -> Map k a
insertMax kx x t
= case t of
Tip -> Test.singleton kx x
Bin _ ky y l r
-> balanceR ky y l (insertMax kx x r)
insertMin kx x t
= case t of
Tip -> Test.singleton kx x
Bin _ ky y l r
-> balanceL ky y (insertMin kx x l) r
splitLookup :: Ord k => k -> Map k a -> (Map k a,Maybe a,Map k a)
splitLookup k0 m = case go k0 m of
StrictTriple l mv r -> (l, mv, r)
where
go :: Ord k => k -> Map k a -> StrictTriple (Map k a) (Maybe a) (Map k a)
go !k t =
case t of
Tip -> StrictTriple Tip Nothing Tip
Bin _ kx x l r -> case compare k kx of
LT -> let StrictTriple lt z gt = go k l
!gt' = link kx x gt r
in StrictTriple lt z gt'
GT -> let StrictTriple lt z gt = go k r
!lt' = link kx x l lt
in StrictTriple lt' z gt
EQ -> StrictTriple l (Just x) r
{-# INLINABLE splitLookup #-}
data StrictTriple a b c = StrictTriple !a !b !c
insertWithKey :: Ord k => (k -> a -> a -> a) -> k -> a -> Map k a -> Map k a
insertWithKey = go
where
go :: Ord k => (k -> a -> a -> a) -> k -> a -> Map k a -> Map k a
go _ !kx x Tip = Test.singleton kx x
go f kx x (Bin sy ky y l r) =
case compare kx ky of
LT -> balanceL ky y (go f kx x l) r
GT -> balanceR ky y l (go f kx x r)
EQ -> Bin sy kx (f kx x y) l r
{-# INLINABLE insertWithKey #-}
insertWithKeyR :: Ord k => (k -> a -> a -> a) -> k -> a -> Map k a -> Map k a
insertWithKeyR = go
where
go :: Ord k => (k -> a -> a -> a) -> k -> a -> Map k a -> Map k a
go _ !kx x Tip = Test.singleton kx x
go f kx x (Bin sy ky y l r) =
case compare kx ky of
LT -> balanceL ky y (go f kx x l) r
GT -> balanceR ky y l (go f kx x r)
EQ -> Bin sy ky (f ky y x) l r
{-# INLINABLE insertWithKeyR #-}
split :: Ord k => k -> Map k a -> (Map k a,Map k a)
split !k0 t0 = toPair $ go k0 t0
where
go k t =
case t of
Tip -> Tip :*: Tip
Bin _ kx x l r -> case compare k kx of
LT -> let (lt :*: gt) = go k l in lt :*: link kx x gt r
GT -> let (lt :*: gt) = go k r in link kx x l lt :*: gt
EQ -> (l :*: r)
{-# INLINABLE split #-}
newtype Component s addr = Component Int
deriving newtype (Eq, Ord)
newtype FanIn a = FanIn{ getFanIn :: First a }
deriving newtype (Semigroup, Monoid)
newtype AddrMap s = AddrMap{ addrMap :: Map Int (FanIn (Index 0x0400)) }
deriving newtype (Monoid)
instance Semigroup (AddrMap s) where
AddrMap map1 <> AddrMap map2 = AddrMap $ unionWithKey (const mappend) map1 map2
newtype Addressing s dat addr a = Addressing
{ unAddressing :: RWS
(FanIn addr, AddrMap s)
(FanIn (Maybe dat), AddrMap s)
Int
a
}
deriving newtype (Functor, Applicative, Monad)
memoryMap
:: Maybe addr
-> (forall s. Addressing s dat addr a)
-> (Maybe dat, a)
memoryMap addr body = (join (firstIn read), x)
where
(x, (read, conns)) = evalRWS (unAddressing body) (fanInMaybe addr, conns) 0
readWrite_
:: ((Maybe (Index 1024)) -> (Maybe dat))
-> Addressing s dat addr (Component s (Index 1024))
readWrite_ mkComponent = Addressing $ do
component@(Component i) <- Component <$> get <* modify succ
(_, addrs) <- ask
let addr = firstIn . fromMaybe mempty $ Test.lookup i (addrMap addrs)
read = mkComponent addr
tell (fanIn read, mempty)
return component
ram0
:: (1 <= n)
=> SNat n
-> Addressing s (Index 1024) addr (Component s (Index 1024))
ram0 size@SNat = readWrite_ $ \addr ->
Just $ negate (fromMaybe 2 addr)
connect
:: Component s (Index 1024)
-> Addressing s dat (Index 1024) ()
connect component@(Component i) = Addressing $ do
(addr, _) <- ask
tell (mempty, AddrMap $ Test.singleton i $ addr)
firstIn :: FanIn a -> Maybe a
firstIn = getFirst . getFanIn
fanInMaybe :: Maybe a -> FanIn a
fanInMaybe = FanIn . First
fanIn :: a -> FanIn a
fanIn = fanInMaybe . pure
matchAddr
:: (addr -> Maybe addr')
-> Addressing s dat addr' a
-> Addressing s dat addr a
matchAddr match body = Addressing $ rws $ \(addr, addrs) s ->
let addr' = fanInMaybe . (match =<<) . firstIn $ addr
in runRWS (unAddressing body) (addr', addrs) s
from
:: forall addr' s dat addr a. (Integral addr, Ord addr, Integral addr', Bounded addr')
=> addr
-> Addressing s dat addr' a
-> Addressing s dat addr a
from base = matchAddr $ \addr -> do
guard $ addr >= base
let offset = addr - base
guard $ offset <= lim
return $ fromIntegral offset
where
lim = fromIntegral (maxBound :: addr')
topEntity
:: Maybe (Index 0x0400)
-> ((Maybe (Index 0x0400)), ())
topEntity addr = memoryMap addr $ do
ram <- ram0 (SNat @0x0400)
from 0x0000 $ connect ram
-- from 0x0400 $ connect ram
I've removed the Ap (Signal dom)
aspect of it, and also removed the unsafeCoerce
, uncommenting the last from 0x0400 $ connect ram
seems to throw Clash into an infinite loop.
One thing I also noticed is that sometimes we have:
\x -> let y = expr_using_x in expr_not_using_y
Which is problamatic because dead code elimination happens at a very late stage because the transformation is deemed expensive: n^2 for n number of let-bindings. But n is in general small before the ANF transform, so perhaps we should run it more often during the constant propagation phase, which is also doing all the inlining. It might be that it's doing all the inlining in the expr_using_x
from the above example.
I've tried adding dead code elimination inside of the main loop, but it doesn't seem to solve the issue.
We don't really have the resources to investigate further (the debug logs are just too big to analyze in a sensible amount of time). I think we must conclude that Clash currently cannot translate the kind of recursive descriptions given here, or those of #1611
Hopefully, the partial evaluation work done at https://github.com/clash-lang/clash-compiler/tree/partial-evaluator-primitives-easier will be able to handle these kind of recursive description properly. The problem there is that the work is far from production ready, and due to circumstances, development on that feature will be halted for the coming year (unless it becomes sponsored).
It thus pains me to say that (typed) template haskell is probably the only way forward at this moment in time.
We don't really have the resources to investigate further (the debug logs are just too big to analyze in a sensible amount of time).
By this, do you mean they are too big because Clash is doing a lot of work, or because the code to reproduce this issue is still too large? In other words, is there room for me to try to reduce my code further, or is this a lost cause?
Clash is doing too much work, which is both a result of the size of the test case and fact it seems to get stuck in an inlining loop. But the logs are huge (thousands of transformations, order of gigabytes size), and so it's hard to pin down whether one of the transformations is doing something dumb/wrong or where a (slightly) different order/strategy of the transformations would lead to termination.
Anyhow, I've managed to get something which does compile while still being close to the original code in spirit:
{-# LANGUAGE DerivingStrategies, GeneralizedNewtypeDeriving #-}
module Test3 where
import Clash.Prelude
import Data.Maybe
import Control.Monad
import Control.Monad.RWS
newtype Component addr = Component Int
deriving newtype (Eq, Ord)
newtype FanIn a = FanIn{ getFanIn :: First a }
deriving newtype (Semigroup, Monoid)
newtype AddrMap = AddrMap{ addrMap :: [(Int,(FanIn (Index 0x0400)))] }
deriving newtype (Monoid)
instance Semigroup (AddrMap) where
AddrMap map1 <> AddrMap map2 = AddrMap $ unionWithKeyList (const mappend) map1 map2
unionWithKeyList :: Ord k => (k -> a -> a -> a) -> [(k,a)] -> [(k,a)] -> [(k,a)]
unionWithKeyList f l r = foldList (insertWithKeyList f) r l
foldList :: (a -> b -> b) -> b -> [a] -> b
foldList _ z [] = z
foldList f z (x:xs) = foldList f (f x z) xs
insertWithKeyList :: Ord k => (k -> a -> a -> a) -> (k,a) -> [(k,a)] -> [(k,a)]
insertWithKeyList _ k [] = [k]
insertWithKeyList f (k,a) ((k1,b):xs) = case compare k k1 of
LT -> (k,a):(k1,b):xs
EQ -> (k,f k a b) : xs
GT -> (k1,b):insertWithKeyList f (k,a) xs
lookupList :: Eq k => k -> [(k,a)] -> Maybe a
lookupList _ [] = Nothing
lookupList k ((k1,a):xs) = if k == k1 then Just a else lookupList k xs
singletonList :: k -> a -> [(k,a)]
singletonList k a = [(k,a)]
newtype Addressing dat addr a = Addressing
{ unAddressing :: RWS
(FanIn addr, AddrMap)
(FanIn (Maybe dat), AddrMap)
Int
a
}
deriving newtype (Functor, Applicative, Monad)
memoryMap
:: Maybe addr
-> (Addressing dat addr a)
-> (Maybe dat, a)
memoryMap addr body = (join (firstIn read), x)
where
(x, (read, conns)) = evalRWS (unAddressing body) (fanInMaybe addr, conns) 0
readWrite_
:: ((Maybe (Index 1024)) -> (Maybe dat))
-> Addressing dat addr (Component (Index 1024))
readWrite_ mkComponent = Addressing $ do
component@(Component i) <- Component <$> get <* modify succ
(_, addrs) <- ask
let addr = firstIn . fromMaybe mempty $ lookupList i (addrMap addrs)
read = mkComponent addr
tell (fanIn read, mempty)
return component
ram0
:: (1 <= n)
=> SNat n
-> Addressing (Index 1024) addr (Component (Index 1024))
ram0 size@SNat = readWrite_ $ \addr ->
Just $ negate (fromMaybe 2 addr)
connect
:: Component (Index 1024)
-> Addressing dat (Index 1024) ()
connect component@(Component i) = Addressing $ do
(addr, _) <- ask
tell (mempty, AddrMap $ singletonList i $ addr)
firstIn :: FanIn a -> Maybe a
firstIn = getFirst . getFanIn
fanInMaybe :: Maybe a -> FanIn a
fanInMaybe = FanIn . First
fanIn :: a -> FanIn a
fanIn = fanInMaybe . pure
matchAddr
:: (addr -> Maybe addr')
-> Addressing dat addr' a
-> Addressing dat addr a
matchAddr match body = Addressing $ rws $ \(addr, addrs) s ->
let addr' = fanInMaybe . (match =<<) . firstIn $ addr
in runRWS (unAddressing body) (addr', addrs) s
from
:: forall addr' dat addr a. (Integral addr, Ord addr, Integral addr', Bounded addr')
=> addr
-> Addressing dat addr' a
-> Addressing dat addr a
from base = matchAddr $ \addr -> do
guard $ addr >= base
let offset = addr - base
guard $ offset <= lim
return $ fromIntegral offset
where
lim = fromIntegral (maxBound :: addr')
topEntity
:: Maybe (Index 0x0400)
-> ((Maybe (Index 0x0400)), ())
topEntity addr = memoryMap addr $ do
ram <- ram0 (SNat @0x0400)
from 0x0000 $ connect ram
from 0x0200 $ connect ram
I think slowly building this code back up to the intended use would be a more fruitful exercise than trying figure out how we could get the original code to compile. I would go towards building up in this order:
Ap Signal
againblockRam
againunsafeCoerce
again.Perhaps there's a step 3.5 between 3 and 4 so that connect
has a polymorphic type signature again, but perhaps that requires the unsafeCoerce
of step 4. You'll need to synthesize often to make sure it keeps working, and report back when it stops working. As you can see, when you build back up, you cannot depend on recursive functions from pre-compiled dependencies as they might not have an unfolding. Perhaps that would be a step 5, try and use functions from pre-compiled dependencies.
I think slowly building this code back up to the intended use would be a more fruitful exercise than trying figure out how we could get the original code to compile.
This is great stuff!
I managed to get it back to the unsafeCoerce
-using version (albeit without testing its runtime behaviour yet... but hey, it compiles!) using your alist-for-Map
idea (see this version). Then, when I try to apply the same idea to DMap
(i.e. an assoc-list of DSum k f
s), then I get the following which I think could be the result of an easy-to-fix oversight:
src/Board.hs:17:1: error:
Hit specialisation limit 100 on function `c$Board.topEntity_go_go[4436866]'.
The function `c$Board.topEntity_go_go[4436866] :: GHC.Prim.Int#[3674937295934324764]
-> GHC.Ptr.Ptr[3674937295934324890]
GHC.Word.Word8[3674937295934324860]
-> GHC.Prim.Addr#[3674937295934324738]
-> GHC.Types.[][3674937295934324788]
GHC.Word.Word8[3674937295934324860]
-> GHC.Prim.Int#[3674937295934324764]
-> GHC.Prim.State#[3674937295934324836]
GHC.Prim.RealWorld[3674937295934324808]
-> GHC.Prim.(#,#)[3819052484010180612]
(GHC.Types.TupleRep[3891110078048108760]
(GHC.Types.[][3891110078048108577]
GHC.Types.RuntimeRep[3674937295934324926]))
GHC.Types.LiftedRep[3891110078048108766]
(GHC.Prim.State#[3674937295934324836]
GHC.Prim.RealWorld[3674937295934324808])
GHC.Fingerprint.Type.Fingerprint[8214565720323785011]' is most likely recursive, and looks like it is being indefinitely specialized on a growing argument.
Body of `c$Board.topEntity_go_go[4436866] :: GHC.Prim.Int#[3674937295934324764]
-> GHC.Ptr.Ptr[3674937295934324890]
GHC.Word.Word8[3674937295934324860]
-> GHC.Prim.Addr#[3674937295934324738]
-> GHC.Types.[][3674937295934324788]
GHC.Word.Word8[3674937295934324860]
-> GHC.Prim.Int#[3674937295934324764]
-> GHC.Prim.State#[3674937295934324836]
GHC.Prim.RealWorld[3674937295934324808]
-> GHC.Prim.(#,#)[3819052484010180612]
(GHC.Types.TupleRep[3891110078048108760]
(GHC.Types.[][3891110078048108577]
GHC.Types.RuntimeRep[3674937295934324926]))
GHC.Types.LiftedRep[3891110078048108766]
(GHC.Prim.State#[3674937295934324836]
GHC.Prim.RealWorld[3674937295934324808])
GHC.Fingerprint.Type.Fingerprint[8214565720323785011]':
λ(ww2[8214565720324017915] :: GHC.Prim.Int#[3674937295934324764]) ->
λ(ptr[8214565720324017917] :: GHC.Ptr.Ptr[3674937295934324890]
GHC.Word.Word8[3674937295934324860]) ->
λ(a[8214565720324017934] :: GHC.Prim.Addr#[3674937295934324738]) ->
λ(ds[8214565720324017942] :: GHC.Types.[][3674937295934324788]
GHC.Word.Word8[3674937295934324860]) ->
λ(ds1[8214565720324017943] :: GHC.Prim.Int#[3674937295934324764]) ->
λ(eta2[8214565720324017944] :: GHC.Prim.State#[3674937295934324836]
GHC.Prim.RealWorld[3674937295934324808]) ->
case ds[8214565720324017942][LocalId] of
GHC.Types.[][3891110078048108577] ->
c$Board.topEntity_exit[14273][GlobalId]
ww2[8214565720324017915][LocalId]
ptr[8214565720324017917][LocalId]
eta2[8214565720324017944][LocalId]
GHC.Types.:[3891110078048108550]
(val1[8214565720324017949] :: GHC.Word.Word8[3674937295934324860])
(vals2[8214565720324017950] :: GHC.Types.[][3674937295934324788]
GHC.Word.Word8[3674937295934324860]) ->
case val1[8214565720324017949][LocalId] of
GHC.Word.W8#[3891110078048108583]
(x1[8214565720324017954] :: GHC.Prim.Word#[3674937295934324854]) ->
letrec
s1[8214565720324017956] :: GHC.Prim.State#[3674937295934324836]
GHC.Prim.RealWorld[3674937295934324808]
= GHC.Prim.writeWord8OffAddr#
@GHC.Prim.RealWorld[3674937295934324808]
a[8214565720324017934][LocalId]
ds1[8214565720324017943][LocalId]
x1[8214565720324017954][LocalId]
eta2[8214565720324017944][LocalId]
in case s1[8214565720324017956][LocalId] of
_ ->
c$Board.topEntity_go_go[4436866][GlobalId]
ww2[8214565720324017915][LocalId]
ptr[8214565720324017917][LocalId]
a[8214565720324017934][LocalId]
vals2[8214565720324017950][LocalId]
(GHC.Prim.+# ds1[8214565720324017943][LocalId]
1)
s1[8214565720324017956][LocalId]
Argument (in position: 4) that triggered termination:
GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
(GHC.Prim.+#
1
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1)
1
Run with '-fclash-spec-limit=N' to increase the specialisation limit to N.
The source location of the error is not exact, only indicative, as it is acquired
after optimizations. The actual location of the error can be in a function that is
inlined. To prevent inlining of those functions, annotate them with a NOINLINE pragma.
|
17 | topEntity addr wr = memoryMap addr wr $ do
| ^^^^^^^^^
Note, however, that I can probably make do with the unsafeCoerce
-using variant, so I'll do further testing after the holidays and if this works I will be good to go!
This will be quite difficult to minimize... I have uploaded the whole shebang to https://github.com/gergoerdi/clash-spaceinvaders/tree/clash-bug-reduceBindersCleanup.
Naive bisection shows that the first change on my side that causes it is somewhere between https://github.com/gergoerdi/clash-intel8080/commits/66ca632 and https://github.com/gergoerdi/clash-intel8080/commits/ff9e07b (change rendered: https://github.com/gergoerdi/clash-intel8080/compare/66ca632..ff9e07b)