clash-lib
Copyright(C) 2012-2016 University of Twente
2016-2017 Myrtle Software Ltd
2017-2022 Google Inc.
2021-2026 QBayLogic B.V.
LicenseBSD2 (see the file LICENSE)
MaintainerQBayLogic B.V. <devops@qbaylogic.com>
Safe HaskellSafe-Inferred
LanguageHaskell2010

Clash.Normalize.Transformations.Case

Description

Transformations on case-expressions

Synopsis

Documentation

caseCase :: Transformation Source #

Move a Case-decomposition from the subject of a Case-decomposition to the alternatives

caseConWorker :: HasCallStack => TransformContext -> Term -> Term -> Type -> [Alt] -> NormalizeSession Term Source #

The Case handler of caseCon: tries caseOneAlt first and only when that did not fire, caseCon'. See NOTE: caseOneAlt before caseCon'.

caseDataToTag :: Transformation Source #

Turn a case-expression on the constructor tag of a value into a case-expression on the value itself. For example, GHC derives == for

data Mode = Idle | Counting | Done

by comparing the tags of the constructors, so that mode == Done becomes:

case dataToTag# mode of
  2# -> True
  _  -> False

which we rewrite to:

case mode of
  Done -> True
  _    -> False

Without this, ANF binds the subject dataToTag# mode to a new variable, so the HDL holds the tag in a signal as wide as an Int, with a name like c$case_scrut that says nothing about the value it's the tag of. After the rewrite, the HDL compares the value itself, and the alternatives of the case-expression mention the constructors they match.

Fields of the matched constructors are bound to variables that the alternatives don't reference.

caseEliminateNonReachable :: Transformation Source #

Remove non-reachable alternatives. For example, consider:

data STy ty where
  SInt :: Int -> STy Int
  SBool :: Bool -> STy Bool

f :: STy ty -> ty
f (SInt b) = b + 1
f (SBool True) = False
f (SBool False) = True
{-# NOINLINE f #-}

g :: STy Int -> Int
g = f

f is always specialized on STy Int. The SBool alternatives are therefore unreachable. Additional information can be found at: https://github.com/clash-lang/clash-compiler/pull/465

caseFlat :: Transformation Source #

Flatten ridiculous case-statements generated by GHC

For case-statements in haskell of the form:

f :: Unsigned 4 -> Unsigned 4
f x = case x of
  0 -> 3
  1 -> 2
  2 -> 1
  3 -> 0

GHC generates Core that looks like:

f = \(x :: Unsigned 4) -> case x == fromInteger 3 of
                            False -> case x == fromInteger 2 of
                              False -> case x == fromInteger 1 of
                                False -> case x == fromInteger 0 of
                                  False -> error "incomplete case"
                                  True  -> fromInteger 3
                                True -> fromInteger 2
                              True -> fromInteger 1
                            True -> fromInteger 0

Which would result in a priority decoder circuit where a normal decoder circuit was desired.

This transformation transforms the above Core to the saner:

f = \(x :: Unsigned 4) -> case x of
       _ -> error "incomplete case"
       0 -> fromInteger 3
       1 -> fromInteger 2
       2 -> fromInteger 1
       3 -> fromInteger 0

caseLet :: Transformation Source #

Lift the let-bindings out of the subject of a Case-decomposition

elimExistentials :: Transformation Source #

Tries to eliminate existentials by using heuristics to determine what the existential should be. For example, consider Vec:

data Vec :: Nat -> Type -> Type where Nil :: Vec 0 a Cons x xs :: a -> Vec n a -> Vec (n + 1) a

Thus, null (annotated with existentials) could look like:

null :: forall n . Vec n Bool -> Bool null v = case v of Nil {n ~ 0} -> True Cons {n1:Nat} {n~n1+1} (x :: a) (xs :: Vec n1 a) -> False

When it's applied to a vector of length 5, this becomes:

null :: Vec 5 Bool -> Bool null v = case v of Nil {5 ~ 0} -> True Cons {n1:Nat} {5~n1+1} (x :: a) (xs :: Vec n1 a) -> False

This function solves n1 and replaces every occurrence with its solution. A very limited number of solutions are currently recognized: only adds (such as in the example) will be solved.

elimCaseBigNumInternals :: Transformation Source #

This finds cases on Integers and Naturals and rewrites them to remove the alternatives with bignums/bytearrays in them.

Natural and Integer are defined as: data Natural = NS Word# | NB ByteArray# data Integer = IS Int# | IP ByteArray# | IN ByteArray# Both Natural and HWType have invariants stating that they will only use NBIPIN when their values doesn't fit in NS/IS. And the code in base also makes use of that. So we can be sure that small values, that are representable in HDL, are always encoded with NS/IS.

Because the NBIPIN don't/can't exist in HDL, this transformation looks for case with patterns for NS/IS and just always picks those alternatives, and removes the other alternatives.

This is as "safe" as the rest of the Natural/Integer handling that clash does in HDL, because numbers bigger then Word/Int can't exist there anyway.