clash-lang / clash-compiler

Haskell to VHDL/Verilog/SystemVerilog compiler
https://clash-lang.org/
Other
1.4k stars 147 forks source link

Non-termination while emitting Verilog #199

Open strake opened 7 years ago

strake commented 7 years ago

Source file:

module Test where

import CLaSH.Prelude

f :: BitVector 5 -> Maybe (Bit -> Bit -> Bit)
f i = case slice d1 d0 i of
    2 -> op
    3 -> op
    _ -> Nothing
  where op :: Maybe (Bit -> Bit -> Bit)
        op = case (slice d4 d2 i, b) of
            (0, 0) -> Just (+)
            (1, 0) -> Just (+)
            (2, 0) -> Just (+)
            (3, 0) -> Just (+)
            (4, 0) -> Just (+)
            (5, 0) -> Just (+)
            _ -> Nothing
          where b :: Bit
                b = case i ! 0 of
                    0 -> 0
                    1 -> 0

topEntity :: BitVector 5 -> Bit -> Bit -> Maybe Bit
topEntity = (sequenceA .) . sequenceA . f

What happens:

$ clash --interactive Test
CLaSHi, version 0.7 (using clash-lib, version 0.7):
http://www.clash-lang.org/  :? for help
[1 of 1] Compiling Test             ( Test.hs, interpreted )
Ok, modules loaded: Test.
*Test> :verilog
Loading dependencies took 1.160223104s
CLaSH.Normalize.Transformations(193): InlineNonRep: Test.topEntity_fail411 already inlined 20 times in:Test.topEntity1912677930
Type of the subject is: GHC.Base.Maybe
  (CLaSH.Sized.Internal.BitVector.BitVector 1
   -> CLaSH.Sized.Internal.BitVector.BitVector 1
   -> CLaSH.Sized.Internal.BitVector.BitVector 1)
Function Test.topEntity1912677930 will not reach a normal form, and compilation might fail.
Run with '-clash-inline-limit=N' to increase the inlining limit to N.
<Last 7 lines repeated many times>

I tried '-clash-inline-limit=48', in which case it does the same as above, and '-clash-inline-limit=256', in which case it uses all my memory, then dies to seg fault.

It emits code normally on deleting one of the non-_ cases in the definition of op or f i, or redefining b = 0.

christiaanb commented 7 years ago

Thanks for the test case, seems to show some quadratic (or maybe even exponential) behaviour in the compiler. This might take some time to fix.

christiaanb commented 7 years ago

I do manage to compile with:

$ stack exec clash -- +RTS -s -RTS --vhdl -clash-inline-limit=63 examples/Test1.hs
Loading dependencies took 2.440673s
Applied 1940 transformations
Normalisation took 4.669512s
Netlist generation took 0.006009s
Testbench generation took 0.000189s
Total compilation took 7.118191s
   8,890,720,760 bytes allocated in the heap
   1,714,875,712 bytes copied during GC
      80,515,000 bytes maximum residency (27 sample(s))
       6,338,184 bytes maximum slop
             195 MB total memory in use (0 MB lost due to fragmentation)

                                     Tot time (elapsed)  Avg pause  Max pause
  Gen  0     17000 colls,     0 par    1.144s   1.157s     0.0001s    0.0009s
  Gen  1        27 colls,     0 par    0.840s   0.933s     0.0346s    0.0966s

  INIT    time    0.000s  (  0.000s elapsed)
  MUT     time    4.816s  (  5.103s elapsed)
  GC      time    1.984s  (  2.090s elapsed)
  EXIT    time    0.004s  (  0.010s elapsed)
  Total   time    6.828s  (  7.204s elapsed)

  %GC     time      29.1%  (29.0% elapsed)

  Alloc rate    1,846,079,892 bytes per MUT second

  Productivity  70.9% of total user, 67.2% of total elapsed
strake commented 7 years ago

Ah, so it does... but that also fails if i add 2 more cases to the definition of op.

The test case i posted is reduced from some other code i want to compile. Indeed the failures seem due to the same superlinear behavior.