clash-lib-1.8.4: Clash: a functional hardware description language - As a library

Copyright | (C) 2012-2016 University of Twente 2016-2017 Myrtle Software Ltd 2017-2018 Google Inc. 2021-2023 QBayLogic B.V.
License | BSD2 (see the file LICENSE)
Maintainer | QBayLogic B.V. <devops@qbaylogic.com>
Safe Haskell | None
Language | Haskell2010

Clash.Normalize.Transformations.Specialize

Description

Transformations for specialization

Synopsis

- appProp :: HasCallStack => NormRewrite
- constantSpec :: HasCallStack => NormRewrite
- specialize :: NormRewrite
- nonRepSpec :: HasCallStack => NormRewrite
- typeSpec :: HasCallStack => NormRewrite
- zeroWidthSpec :: HasCallStack => NormRewrite

# Documentation

appProp :: HasCallStack => NormRewrite Source #

Propagate arguments of application inwards; except for `Lam` where the argument becomes let-bound. `appProp` tries to propagate as many arguments as possible, down as many levels as possible; and should be called in a top-down traversal.

The idea is that this reduces the number of traversals, which hopefully leads to shorter compile times.

Note [AppProp no shadowing]

Case 1.

Imagine:

    (case x of
       D a b -> h a) (f x y)

rewriting this to:

    let b = f x y
    in  case x of
          D a b -> h a b

is very bad because `b` in `h a b` is now bound by the pattern instead of the newly introduced let-binding

instead we must deshadow w.r.t. the new variable and rewrite to:

    let b = f x y
    in  case x of
          D a b1 -> h a b

Case 2.

Imagine

    (\x -> e) u

where `u` has a free variable named `x`, rewriting this to:

    let x = u
    in  e

would be very bad, because the let-binding suddenly captures the free variable in `u`. To prevent this from happening we over-approximate and check whether `x` is in the current InScopeSet, and deshadow if that's the case, i.e. we then rewrite to:

    let x1 = u
    in  e [x:=x1]

Case 3.

The same for:

    (let x = w in e) u

where `u` again has a free variable `x`, rewriting this to:

    let x = w in (e u)

would be bad because the let-binding now captures the free variable in `u`.

To prevent this from happening, we unconditionally deshadow the function part of the application w.r.t. the free variables in the argument part of the application. It is okay to over-approximate in this case and deshadow w.r.t the current InScopeSet.

constantSpec :: HasCallStack => NormRewrite Source #

Specialize functions on arguments which are constant, except when they are clock, reset generators.

specialize :: NormRewrite Source #

Specialize an application on its argument

nonRepSpec :: HasCallStack => NormRewrite Source #

Specialize functions on their non-representable argument

typeSpec :: HasCallStack => NormRewrite Source #

Specialize functions on their type

zeroWidthSpec :: HasCallStack => NormRewrite Source #

Specialize functions on arguments which are zero-width. These arguments can have only one possible value, and specializing on this value may create additional opportunities for transformations to fire.

As we can't remove zero-width arguements (as transformations cannot change the type of a term), we instead substitute all occurances of a lambda-bound variable with a zero-width type with the only value of that type.