clash-lang / clash-compiler

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

Warn against non-opaque primitive functions on GHC >= 9.4 #2511

Closed martijnbastiaan closed 1 year ago

martijnbastiaan commented 1 year ago

In order for Clash to work properly, some names need to remain untouched by GHC's compilation process. Examples of these names include top entities annotated with a Synthesize pragma, or functions having an associated black box implementation. For the longest time, we have tried to instruct GHC to do so by marking functions as "no inline":

myFunction :: Unsigned 8 -> Unsigned 8
myFunction = (+1)
{-# NOINLINE myFunction #-}

While this does work in the majority of cases, GHC will still touch the name of this function in some, making Clash fail to recognize it. Hence, GHC 9.4 introduce a new pragma OPAQUE:

myFunction :: Unsigned 8 -> Unsigned 8
myFunction = (+1)
{-# OPAQUE myFunction #-}

This PR introduces a change making Clash warn against usage of NOINLINE on GHCs 9.4 and newer. To remain compatible with older GHCs, Clash's code base itself defines a CPP macro that defines CLASH_OPAQUE as either NOINLINE or OPAQUE depending on the version of GHC the code base is compiled with. This means that you'll find the following pattern across it:

myFunction :: Unsigned 8 -> Unsigned 8
myFunction = (+1)
{-# CLASH_OPAQUE myFunction #-} -- Expands to NOINLINE < 9.4
                                -- Expands to OPAQUE >= 9.4

This macro is local to Clash itself, and is not reusable within other projects. If your project suffers from similar cross-compatibility problems, consider using a similar strategy.


Warn against non-opaque primitive functions on GHC >= 9.4.

Fixes #2510

Still TODO:

leonschoorl commented 1 year ago

Now that we're properly marking all primitives as OPAQUE, we could try re-enabling the worker/wrapper transform on clash-prelude when compiling with GHC >= 9.4.

martijnbastiaan commented 1 year ago

This PR has been scripted for 99%. Here are the steps:

  1. In VSCode search for ^\{-# NOINLINE (.*) #-\}, replace with -- See: https://github.com/clash-lang/clash-compiler/pull/2511\n{-# CLASH_OPAQUE $1 #-} in clash-prelude,clash-cores,benchmark,tests/shouldwork,tests/shouldfail,examples.
  2. Create a file need_cpp using git status --short | grep -E '^ M ' | grep -E '.hs$' | sed 's/^ M //g' > need_cpp
  3. Add CPP pragmas everywhere by running 🍝 python3 cppaghetti.py 🍝.