Compiler issue: Normalize/DEC.hs:385:13-45: Non-exhaustive patterns in Just tupTcNm

35 views
Skip to first unread message

peter.t...@gmail.com

unread,
Feb 16, 2021, 2:22:15 PM2/16/21
to Clash - Hardware Description Language
I failed to figure out how to raise a new issue on the github page. (I use sourceforge, not github, mercurial, not git. Apologies)

System verilog synthesis with clash 1.2.4 yields this error. No obvious cause or location in the code for synthesis, which compiles and runs fine, and should contain no non-synthesizable constructs, but is of reasonable size (2570 lines, plus pulled in modules). Synthesis usually works for me and has worked for all other modules in this project.

GHC: Parsing and optimising modules took: 2m50.393s
GHC: Loading external modules from interface files took: 0.037s
GHC: Parsing annotations took: 0.111s
Clash: Parsing and compiling primitives took 0.282s
GHC+Clash: Loading modules cumulatively took 4m49.327s
Clash: Compiling KPU.Read.topEntity
<no location info>: error:
    Other error:
    src/Clash/Normalize/DEC.hs:385:13-45: Non-exhaustive patterns in Just tupTcNm

That is:

            Just tupTcNm = IM.lookup m tupTcm               <--- here
            Just tupTc   = lookupUniqMap tupTcNm tcm

So I presume lookup has returned Nothing. An unnamed tuple value for synthesis? I would suggest a case statement instead of a pattern match, plus an error message as to _what_ it is looking up in the case of a Nothing result, which may give a clue.



Christiaan Baaij

unread,
Feb 16, 2021, 2:48:35 PM2/16/21
to clash-l...@googlegroups.com
Thanks for the report. We're tracking the bug at: https://github.com/clash-lang/clash-compiler/issues/1669

--
You received this message because you are subscribed to the Google Groups "Clash - Hardware Description Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clash-languag...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/clash-language/8d778ecf-1dd6-420f-bb2c-62b5f0981f91n%40googlegroups.com.

Christiaan Baaij

unread,
Feb 16, 2021, 3:14:21 PM2/16/21
to clash-l...@googlegroups.com
Just to confirm my suspicions: would it be possible that  your code has functions with more than 62 arguments? For arguments at the core level we also count the constraints, e.g. for our purposes the function:

f :: (Constraint a, Constraint b, Constraint c) => a -> b -> c

has 5 arguments.

peter.t...@gmail.com

unread,
Feb 16, 2021, 3:53:01 PM2/16/21
to Clash - Hardware Description Language
I thought it would be that too (I recall the bundle constructions in the manual!) but I do not see anything obviously in the code of the subject module like that. Nevertheless there may be something pulled in from some supporting module. I will need to think further about it to locate it. But I believe you are right.

Thank you for pointing out that constraints also count. I'll look for that as well as the explicit possibility.

Peter 

peter.t...@gmail.com

unread,
Feb 16, 2021, 4:17:34 PM2/16/21
to Clash - Hardware Description Language
By the way .. do n-tuples as arguments count as one, or n? Might not functions which need more arguments be constructed artificially by substitution of one function in another during normalization? (surely that would be common? - I presume the number of constraints do not accumulate, on the other hand)

I still don't see anything explicitly suspicious in the code, but it must surely be as you indicate. Arguments plus constraints tend to max out around 20 at most .. provided  tuples of tuples don't flatten and tuples don't count as many. Even so, I don't see it yet. I'll think further and experiment.

Peter

peter.t...@gmail.com

unread,
Feb 16, 2021, 5:29:03 PM2/16/21
to Clash - Hardware Description Language


An answer is suggested by the experiment of NOINLINE-ing every function in sight in the code being sythesized. It synthesizes. No change made to the supporting modules.

So the hypothesis that a function with a large number of arguments is constructed by normalization, and then exceeds the limit ("62"), is not rejected by that.

The circumstantial evidence favors it at present.

Peter

peter.t...@gmail.com

unread,
Feb 16, 2021, 9:04:46 PM2/16/21
to Clash - Hardware Description Language

The straw that breaks the camel's back turns out to be allowing a certain function to be inlined for normalization that is the state transformer of a  mealy machine. The mealy machine itself is marked NOINLINE.

But I don' t understand how one can do inlining/substitution in a mealy machine, which is the only place that function appears ... the logical functionality is just that of the state transformer, and the mealy machine just returns the output to the input each cycle. What is there to substitute through what in that? What can be the difference that it makes if the state transformer is marked NOINLINE versus if it is not so-marked?

Perhaps the logic of that single loop could be pushed up further towards the exterior if the mealy machine is called inside another machine, but the machine itself is still marked NOINLINE, so that should not happen.

Mystifying!

Peter

Christiaan Baaij

unread,
Feb 17, 2021, 2:50:33 AM2/17/21
to clash-l...@googlegroups.com
Yeah, I just realised that it might not even be a function in the user's code that has more than 62 arguments.
It could very well be a function that Clash creates through a process called specialisation, that is, in certain cases given an applied function `f`:

f a b (g c d e)

Clash will transform that to:

f_spec a b c d e

where the definition of f_spec is going to be:

f_spec = \a b c d e -> orignal_body_of_f a b (g c d e)

Thus increasing the number of arguments, and through it also increase the tuple-size created by this DEC transformation.
Note that this `g` doesn't have to be a function, it could also be a data-constructor (e.g. a tuple constructor).
And of course this doesn't only apply to the last argument, e.g. if we had a different f:

f a b (g c d e) (h p q r)

Clash will under certain circumstances transform that to:

f_spec a b c d e p q r

And you can see how one might exceed 62 arguments.

Regardless, I know how to fix the bug in the Clash compiler: generate nested tuples in the DEC transformation in order not to exceed the maximum tuple size.
In the meantime, if I understand correctly you did find a work-around though the use of (NO)INLINE annotations, is that correct?

-- Christiaan

peter.t...@gmail.com

unread,
Feb 17, 2021, 5:21:03 AM2/17/21
to Clash - Hardware Description Language
Thank you very much for posting the issue to github. Yes, strategic use of NOINLINE currently has the code synthesizing.

Also thank you for that explanation, which gives me more intuition. There is  potential for an explosion of repeated formal arguments when subroutines are called in a routine (subfunctions in a function) and the body of the subroutine is substituted in the body of the caller, because the formal arguments to the parent will have been embedded in the arguments to the child.

I am just trying to figure out what I should control ..  should I NOINLINE the parent  or the child - or the grandparent or grandchild? The problem seems to be that writing generically leaves formal arguments hanging around everywhere until they are "finally" specialised for the purposes of synthesis.

What you have said about type constraints indicates that those too may "hang around"  until the last moment.

I hope that the plan to not flatten tuples will help the issue in practice, but I would fear the potential still remains for  subexpressions to blow up. There are even type expressions in ML that are super-exponentially complex to resolve. The user's problem is to control that kind of thing with only a vague idea of what is happening! I'll watch out for it.

Regards

Peter

peter.t...@gmail.com

unread,
Feb 19, 2021, 9:57:37 PM2/19/21
to Clash - Hardware Description Language
Can one say which of the following forms will load up fewer numbers of arguments somewhere during specialisation? B?

A) foo x y z = ...bar u[x,y,z] v w ...
     bar u v w = ...
B) foo x y z = ... bar u[x,y,z] v w ...
                       where bar u v w = ...
C) foo x y z = let bar u v w = ... in
                        ... bar u[x,y,z] v w ...

Perhaps that should be an exam question ..! No, I haven't measured. My thought is for B.

Regards

Peter
Reply all
Reply to author
Forward
0 new messages