| Copyright | (C) 2012-2016 University of Twente 2016-2017 Myrtle Software Ltd 2017-2022 Google Inc. 2021-2026 QBayLogic B.V. |
|---|---|
| License | BSD2 (see the file LICENSE) |
| Maintainer | QBayLogic B.V. <devops@qbaylogic.com> |
| Safe Haskell | Safe-Inferred |
| Language | Haskell2010 |
Clash.Normalize.Transformations.Case
Description
Transformations on case-expressions
Synopsis
- caseCase :: Transformation
- caseCaseWorker :: HasCallStack => TransformContext -> Term -> Term -> Type -> [Alt] -> NormalizeSession Term
- caseCon :: Transformation
- caseConWorker :: HasCallStack => TransformContext -> Term -> Term -> Type -> [Alt] -> NormalizeSession Term
- caseDataToTag :: Transformation
- caseDataToTagWorker :: HasCallStack => TransformContext -> Term -> Term -> Type -> [Alt] -> NormalizeSession Term
- caseEliminateNonReachable :: Transformation
- caseEliminateNonReachableWorker :: HasCallStack => TransformContext -> Term -> Term -> Type -> [Alt] -> NormalizeSession Term
- caseFlat :: Transformation
- caseFlatWorker :: HasCallStack => TransformContext -> Term -> Term -> Type -> [Alt] -> NormalizeSession Term
- caseLet :: Transformation
- caseLetWorker :: HasCallStack => TransformContext -> Term -> Term -> Type -> [Alt] -> NormalizeSession Term
- caseOneAlt :: Term -> NormalizeSession Term
- elimExistentials :: Transformation
- elimExistentialsWorker :: HasCallStack => TransformContext -> Term -> Term -> Type -> [Alt] -> NormalizeSession Term
- elimCaseBigNumInternals :: Transformation
- elimCaseBigNumInternalsWorker :: HasCallStack => TransformContext -> Term -> Term -> Type -> [Alt] -> NormalizeSession Term
Documentation
caseCase :: Transformation Source #
Move a Case-decomposition from the subject of a Case-decomposition to the alternatives
caseCaseWorker :: HasCallStack => TransformContext -> Term -> Term -> Type -> [Alt] -> NormalizeSession Term Source #
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.
caseDataToTagWorker :: HasCallStack => TransformContext -> Term -> Term -> Type -> [Alt] -> NormalizeSession Term Source #
The Case handler of caseDataToTag.
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
caseEliminateNonReachableWorker :: HasCallStack => TransformContext -> Term -> Term -> Type -> [Alt] -> NormalizeSession Term Source #
The Case handler of caseEliminateNonReachable.
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
caseFlatWorker :: HasCallStack => TransformContext -> Term -> Term -> Type -> [Alt] -> NormalizeSession Term Source #
caseLet :: Transformation Source #
Lift the let-bindings out of the subject of a Case-decomposition
caseLetWorker :: HasCallStack => TransformContext -> Term -> Term -> Type -> [Alt] -> NormalizeSession Term Source #
caseOneAlt :: Term -> NormalizeSession Term Source #
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.
elimExistentialsWorker :: HasCallStack => TransformContext -> Term -> Term -> Type -> [Alt] -> NormalizeSession Term Source #
The Case handler of elimExistentials.
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.
elimCaseBigNumInternalsWorker :: HasCallStack => TransformContext -> Term -> Term -> Type -> [Alt] -> NormalizeSession Term Source #
The Case handler of elimCaseBigNumInternals.