    {-
    (c) The AQUA Project, Glasgow University, 1993-1998

    -}

    {-# LANGUAGE DerivingVia #-}

    {-# OPTIONS_GHC -Wno-incomplete-record-updates #-}

    module GHC.Core.Opt.Stats (
        SimplCount, doSimplTick, doFreeSimplTick, simplCountN,
        pprSimplCount, plusSimplCount, zeroSimplCount,
        isZeroSimplCount, hasDetailedCounts, Tick(..)
      ) where

    import GHC.Prelude

    import GHC.Types.Var
    import GHC.Types.Error

    import GHC.Utils.Outputable as Outputable

    import GHC.Data.FastString

    import Data.List (sortOn)
    import Data.List.NonEmpty (NonEmpty(..))
    import qualified Data.List.NonEmpty as NE
    import Data.Ord
    import Data.Map (Map)
    import qualified Data.Map as Map
    import qualified Data.Map.Strict as MapStrict
    import GHC.Utils.Panic (throwGhcException, GhcException(..))

    getVerboseSimplStats :: (Bool -> SDoc) -> SDoc
    getVerboseSimplStats :: (Bool -> SDoc) -> SDoc
    getVerboseSimplStats = (Bool -> SDoc) -> SDoc
    forall doc. IsOutput doc => (Bool -> doc) -> doc
    getPprDebug          -- For now, anyway

    zeroSimplCount     :: Bool -- ^ -ddump-simpl-stats
                       -> SimplCount
    isZeroSimplCount   :: SimplCount -> Bool
    hasDetailedCounts  :: SimplCount -> Bool
    pprSimplCount      :: SimplCount -> SDoc
    doSimplTick        :: Int -- ^ History size of the elaborate counter
                       -> Tick -> SimplCount -> SimplCount
    doFreeSimplTick    ::             Tick -> SimplCount -> SimplCount
    plusSimplCount     :: SimplCount -> SimplCount -> SimplCount

    data SimplCount
       = VerySimplCount !Int        -- Used when don't want detailed stats

       | SimplCount {
            SimplCount -> Int
    ticks   :: !Int,        -- Total ticks
            SimplCount -> TickCounts
    details :: !TickCounts, -- How many of each type

            SimplCount -> Int
    n_log   :: !Int,        -- N
            SimplCount -> [Tick]
    log1    :: [Tick],      -- Last N events; <= opt_HistorySize,
                                    --   most recent first
            SimplCount -> [Tick]
    log2    :: [Tick]       -- Last opt_HistorySize events before that
                                    -- Having log1, log2 lets us accumulate the
                                    -- recent history reasonably efficiently
         }

    type TickCounts = Map Tick Int

    simplCountN :: SimplCount -> Int
    simplCountN :: SimplCount -> Int
    simplCountN (VerySimplCount Int
    n)         = Int
    n
    simplCountN (SimplCount { ticks :: SimplCount -> Int
    ticks = Int
    n }) = Int
    n

    zeroSimplCount :: Bool -> SimplCount
    zeroSimplCount Bool
    dump_simpl_stats
                    -- This is where we decide whether to do
                    -- the VerySimpl version or the full-stats version
      | Bool
    dump_simpl_stats
      = SimplCount {ticks :: Int
    ticks = Int
    0, details :: TickCounts
    details = TickCounts
    forall k a. Map k a
    Map.empty,
                    n_log :: Int
    n_log = Int
    0, log1 :: [Tick]
    log1 = [], log2 :: [Tick]
    log2 = []}
      | Bool
    otherwise
      = Int -> SimplCount
    VerySimplCount Int
    0

    isZeroSimplCount :: SimplCount -> Bool
    isZeroSimplCount (VerySimplCount Int
    n)         = Int
    nInt -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    ==Int
    0
    isZeroSimplCount (SimplCount { ticks :: SimplCount -> Int
    ticks = Int
    n }) = Int
    nInt -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    ==Int
    0

    hasDetailedCounts :: SimplCount -> Bool
    hasDetailedCounts (VerySimplCount {}) = Bool
    False
    hasDetailedCounts (SimplCount {})     = Bool
    True

    doFreeSimplTick :: Tick -> SimplCount -> SimplCount
    doFreeSimplTick Tick
    tick sc :: SimplCount
    sc@SimplCount { details :: SimplCount -> TickCounts
    details = TickCounts
    dts }
      = SimplCount
    sc { details = dts `addTick` tick }
    doFreeSimplTick Tick
    _ SimplCount
    sc = SimplCount
    sc

    doSimplTick :: Int -> Tick -> SimplCount -> SimplCount
    doSimplTick Int
    history_size Tick
    tick
        sc :: SimplCount
    sc@(SimplCount { ticks :: SimplCount -> Int
    ticks = Int
    tks, details :: SimplCount -> TickCounts
    details = TickCounts
    dts, n_log :: SimplCount -> Int
    n_log = Int
    nl, log1 :: SimplCount -> [Tick]
    log1 = [Tick]
    l1 })
      | Int
    nl Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    >= Int
    history_size = SimplCount
    sc1 { n_log = 1, log1 = [tick], log2 = l1 }
      | Bool
    otherwise          = SimplCount
    sc1 { n_log = nl+1, log1 = tick : l1 }
      where
        sc1 :: SimplCount
    sc1 = SimplCount
    sc { ticks = tks+1, details = dts `addTick` tick }

    doSimplTick Int
    _ Tick
    _ (VerySimplCount Int
    n) = Int -> SimplCount
    VerySimplCount (Int
    nInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    1)

    addTick :: TickCounts -> Tick -> TickCounts
    addTick :: TickCounts -> Tick -> TickCounts
    addTick TickCounts
    fm Tick
    tick = (Int -> Int -> Int) -> Tick -> Int -> TickCounts -> TickCounts
    forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
    MapStrict.insertWith Int -> Int -> Int
    forall a. Num a => a -> a -> a
    (+) Tick
    tick Int
    1 TickCounts
    fm

    plusSimplCount :: SimplCount -> SimplCount -> SimplCount
    plusSimplCount sc1 :: SimplCount
    sc1@(SimplCount { ticks :: SimplCount -> Int
    ticks = Int
    tks1, details :: SimplCount -> TickCounts
    details = TickCounts
    dts1 })
                   sc2 :: SimplCount
    sc2@(SimplCount { ticks :: SimplCount -> Int
    ticks = Int
    tks2, details :: SimplCount -> TickCounts
    details = TickCounts
    dts2 })
      = SimplCount
    log_base { ticks = tks1 + tks2
                 , details = MapStrict.unionWith (+) dts1 dts2 }
      where
            -- A hackish way of getting recent log info
        log_base :: SimplCount
    log_base | [Tick] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null (SimplCount -> [Tick]
    log1 SimplCount
    sc2) = SimplCount
    sc1    -- Nothing at all in sc2
                 | [Tick] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null (SimplCount -> [Tick]
    log2 SimplCount
    sc2) = SimplCount
    sc2 { log2 = log1 sc1 }
                 | Bool
    otherwise       = SimplCount
    sc2

    plusSimplCount (VerySimplCount Int
    n) (VerySimplCount Int
    m) = Int -> SimplCount
    VerySimplCount (Int
    nInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    m)
    plusSimplCount SimplCount
    lhs                SimplCount
    rhs                =
      GhcException -> SimplCount
    forall a. HasCallStack => GhcException -> a
    throwGhcException (GhcException -> SimplCount)
    -> (SDoc -> GhcException) -> SDoc -> SimplCount
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> SDoc -> GhcException
    PprProgramError String
    "plusSimplCount" (SDoc -> SimplCount) -> SDoc -> SimplCount
    forall a b. (a -> b) -> a -> b
    $ [SDoc] -> SDoc
    forall doc. IsDoc doc => [doc] -> doc
    vcat
        [ String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "lhs"
        , SimplCount -> SDoc
    pprSimplCount SimplCount
    lhs
        , String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "rhs"
        , SimplCount -> SDoc
    pprSimplCount SimplCount
    rhs
        ]
           -- We use one or the other consistently

    pprSimplCount :: SimplCount -> SDoc
    pprSimplCount (VerySimplCount Int
    n) = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "Total ticks:" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> Int -> SDoc
    forall doc. IsLine doc => Int -> doc
    int Int
    n
    pprSimplCount (SimplCount { ticks :: SimplCount -> Int
    ticks = Int
    tks, details :: SimplCount -> TickCounts
    details = TickCounts
    dts, log1 :: SimplCount -> [Tick]
    log1 = [Tick]
    l1, log2 :: SimplCount -> [Tick]
    log2 = [Tick]
    l2 })
      = [SDoc] -> SDoc
    forall doc. IsDoc doc => [doc] -> doc
    vcat [String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "Total ticks:    " SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> Int -> SDoc
    forall doc. IsLine doc => Int -> doc
    int Int
    tks,
              SDoc
    blankLine,
              TickCounts -> SDoc
    pprTickCounts TickCounts
    dts,
              (Bool -> SDoc) -> SDoc
    getVerboseSimplStats ((Bool -> SDoc) -> SDoc) -> (Bool -> SDoc) -> SDoc
    forall a b. (a -> b) -> a -> b
    $ \Bool
    dbg -> if Bool
    dbg
              then
                    [SDoc] -> SDoc
    forall doc. IsDoc doc => [doc] -> doc
    vcat [SDoc
    blankLine,
                          String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "Log (most recent first)",
                          Int -> SDoc -> SDoc
    nest Int
    4 ([SDoc] -> SDoc
    forall doc. IsDoc doc => [doc] -> doc
    vcat ((Tick -> SDoc) -> [Tick] -> [SDoc]
    forall a b. (a -> b) -> [a] -> [b]
    map Tick -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr [Tick]
    l1) SDoc -> SDoc -> SDoc
    forall doc. IsDoc doc => doc -> doc -> doc
    $$ [SDoc] -> SDoc
    forall doc. IsDoc doc => [doc] -> doc
    vcat ((Tick -> SDoc) -> [Tick] -> [SDoc]
    forall a b. (a -> b) -> [a] -> [b]
    map Tick -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr [Tick]
    l2))]
              else SDoc
    forall doc. IsOutput doc => doc
    Outputable.empty
        ]

    {- Note [Which transformations are innocuous]
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    At one point (Jun 18) I wondered if some transformations (ticks)
    might be  "innocuous", in the sense that they do not unlock a later
    transformation that does not occur in the same pass.  If so, we could
    refrain from bumping the overall tick-count for such innocuous
    transformations, and perhaps terminate the simplifier one pass
    earlier.

    But alas I found that virtually nothing was innocuous!  This Note
    just records what I learned, in case anyone wants to try again.

    These transformations are not innocuous:

    *** NB: I think these ones could be made innocuous
              EtaExpansion
              LetFloatFromLet

    LetFloatFromLet
        x = K (let z = e2 in Just z)
      prepareRhs transforms to
        x2 = let z=e2 in Just z
        x  = K xs
      And now more let-floating can happen in the
      next pass, on x2

    PreInlineUnconditionally
      Example in spectral/cichelli/Auxil
         hinsert = ...let lo = e in
                      let j = ...lo... in
                      case x of
                        False -> ()
                        True -> case lo of I# lo' ->
                                  ...j...
      When we PreInlineUnconditionally j, lo's occ-info changes to once,
      so it can be PreInlineUnconditionally in the next pass, and a
      cascade of further things can happen.

    PostInlineUnconditionally
      let x = e in
      let y = ...x.. in
      case .. of { A -> ...x...y...
                   B -> ...x...y... }
      Current postinlineUnconditinaly will inline y, and then x; sigh.

      But PostInlineUnconditionally might also unlock subsequent
      transformations for the same reason as PreInlineUnconditionally,
      so it's probably not innocuous anyway.

      One annoying variant is this.  CaseMerge introduces auxiliary bindings
         let b = b' in ...
      This takes another full run of the simplifier to elimiante.  But if
      the PostInlineUnconditionally, replacing b with b', is the only thing
      that happens in a Simplifier run, that probably really is innocuous.
      Perhaps an opportunity here.

    KnownBranch, BetaReduction:
      May drop chunks of code, and thereby enable PreInlineUnconditionally
      for some let-binding which now occurs once

    EtaExpansion:
      Example in imaginary/digits-of-e1
        fail = \void. e          where e :: IO ()
      --> etaExpandRhs
        fail = \void. (\s. (e |> g) s) |> sym g      where g :: IO () ~ S -> (S,())
      --> Next iteration of simplify
        fail1 = \void. \s. (e |> g) s
        fail = fail1 |> Void# -> sym g
      And now inline 'fail'

    CaseMerge:
      case x of y {
        DEFAULT -> case y of z { pi -> ei }
        alts2 }
      ---> CaseMerge
        case x of { pi -> let z = y in ei
                  ; alts2 }
      The "let z=y" case-binder-swap gets dealt with in the next pass
    -}

    pprTickCounts :: Map Tick Int -> SDoc
    pprTickCounts :: TickCounts -> SDoc
    pprTickCounts TickCounts
    counts
      = [SDoc] -> SDoc
    forall doc. IsDoc doc => [doc] -> doc
    vcat ((NonEmpty (Tick, Int) -> SDoc) -> [NonEmpty (Tick, Int)] -> [SDoc]
    forall a b. (a -> b) -> [a] -> [b]
    map NonEmpty (Tick, Int) -> SDoc
    pprTickGroup [NonEmpty (Tick, Int)]
    groups)
      where
        groups :: [NonEmpty (Tick, Int)] -- Each group shares a common tag
                                         -- toList returns common tags adjacent
        groups :: [NonEmpty (Tick, Int)]
    groups = ((Tick, Int) -> Int) -> [(Tick, Int)] -> [NonEmpty (Tick, Int)]
    forall (f :: * -> *) b a.
    (Foldable f, Eq b) =>
    (a -> b) -> f a -> [NonEmpty a]
    NE.groupWith (Tick -> Int
    tickToTag (Tick -> Int) -> ((Tick, Int) -> Tick) -> (Tick, Int) -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Tick, Int) -> Tick
    forall a b. (a, b) -> a
    fst) (TickCounts -> [(Tick, Int)]
    forall k a. Map k a -> [(k, a)]
    Map.toList TickCounts
    counts)

    pprTickGroup :: NonEmpty (Tick, Int) -> SDoc
    pprTickGroup :: NonEmpty (Tick, Int) -> SDoc
    pprTickGroup group :: NonEmpty (Tick, Int)
    group@((Tick
    tick1,Int
    _) :| [(Tick, Int)]
    _)
      = SDoc -> Int -> SDoc -> SDoc
    hang (Int -> SDoc
    forall doc. IsLine doc => Int -> doc
    int (NonEmpty Int -> Int
    forall a. Num a => NonEmpty a -> a
    forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
    sum (((Tick, Int) -> Int) -> NonEmpty (Tick, Int) -> NonEmpty Int
    forall a b. (a -> b) -> NonEmpty a -> NonEmpty b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (Tick, Int) -> Int
    forall a b. (a, b) -> b
    snd NonEmpty (Tick, Int)
    group)) SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> Tick -> SDoc
    pprTickType Tick
    tick1)
           Int
    2 ([SDoc] -> SDoc
    forall doc. IsDoc doc => [doc] -> doc
    vcat [ Int -> SDoc
    forall doc. IsLine doc => Int -> doc
    int Int
    n SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> Tick -> SDoc
    pprTickCts Tick
    tick
                                        -- flip as we want largest first
                   | (Tick
    tick,Int
    n) <- ((Tick, Int) -> Down Int) -> [(Tick, Int)] -> [(Tick, Int)]
    forall b a. Ord b => (a -> b) -> [a] -> [a]
    sortOn (Int -> Down Int
    forall a. a -> Down a
    Down (Int -> Down Int)
    -> ((Tick, Int) -> Int) -> (Tick, Int) -> Down Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Tick, Int) -> Int
    forall a b. (a, b) -> b
    snd) (NonEmpty (Tick, Int) -> [(Tick, Int)]
    forall a. NonEmpty a -> [a]
    NE.toList NonEmpty (Tick, Int)
    group)])

    data Tick  -- See Note [Which transformations are innocuous]
      = PreInlineUnconditionally    Id
      | PostInlineUnconditionally   Id

      | UnfoldingDone               Id
      | RuleFired                   FastString      -- Rule name

      | LetFloatFromLet
      | EtaExpansion                Id      -- LHS binder
      | EtaReduction                Id      -- Binder on outer lambda
      | BetaReduction               Id      -- Lambda binder

      | CaseOfCase                  Id      -- Bndr on *inner* case
      | KnownBranch                 Id      -- Case binder
      | CaseMerge                   Id      -- Binder on outer case
      | AltMerge                    Id      -- Case binder
      | CaseElim                    Id      -- Case binder
      | CaseIdentity                Id      -- Case binder
      | FillInCaseDefault           Id      -- Case binder

      | SimplifierDone              -- Ticked at each iteration of the simplifier

    instance Outputable Tick where
      ppr :: Tick -> SDoc
    ppr Tick
    tick = Tick -> SDoc
    pprTickType Tick
    tick SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> Tick -> SDoc
    pprTickCts Tick
    tick

    instance Eq Tick where
      Tick
    a == :: Tick -> Tick -> Bool
    == Tick
    b = case Tick
    a Tick -> Tick -> Ordering
    `cmpTick` Tick
    b of
               Ordering
    EQ -> Bool
    True
               Ordering
    _ -> Bool
    False

    instance Ord Tick where
      compare :: Tick -> Tick -> Ordering
    compare = Tick -> Tick -> Ordering
    cmpTick

    tickToTag :: Tick -> Int
    tickToTag :: Tick -> Int
    tickToTag (PreInlineUnconditionally Id
    _)  = Int
    0
    tickToTag (PostInlineUnconditionally Id
    _) = Int
    1
    tickToTag (UnfoldingDone Id
    _)             = Int
    2
    tickToTag (RuleFired FastString
    _)                 = Int
    3
    tickToTag Tick
    LetFloatFromLet               = Int
    4
    tickToTag (EtaExpansion Id
    _)              = Int
    5
    tickToTag (EtaReduction Id
    _)              = Int
    6
    tickToTag (BetaReduction Id
    _)             = Int
    7
    tickToTag (CaseOfCase Id
    _)                = Int
    8
    tickToTag (KnownBranch Id
    _)               = Int
    9
    tickToTag (CaseMerge Id
    _)                 = Int
    10
    tickToTag (CaseElim Id
    _)                  = Int
    11
    tickToTag (CaseIdentity Id
    _)              = Int
    12
    tickToTag (FillInCaseDefault Id
    _)         = Int
    13
    tickToTag Tick
    SimplifierDone                = Int
    16
    tickToTag (AltMerge Id
    _)                  = Int
    17

    pprTickType :: Tick -> SDoc
    pprTickType :: Tick -> SDoc
    pprTickType (PreInlineUnconditionally Id
    _) = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "PreInlineUnconditionally"
    pprTickType (PostInlineUnconditionally Id
    _)= String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "PostInlineUnconditionally"
    pprTickType (UnfoldingDone Id
    _)            = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "UnfoldingDone"
    pprTickType (RuleFired FastString
    _)                = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "RuleFired"
    pprTickType Tick
    LetFloatFromLet              = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "LetFloatFromLet"
    pprTickType (EtaExpansion Id
    _)             = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "EtaExpansion"
    pprTickType (EtaReduction Id
    _)             = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "EtaReduction"
    pprTickType (BetaReduction Id
    _)            = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "BetaReduction"
    pprTickType (CaseOfCase Id
    _)               = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "CaseOfCase"
    pprTickType (KnownBranch Id
    _)              = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "KnownBranch"
    pprTickType (CaseMerge Id
    _)                = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "CaseMerge"
    pprTickType (AltMerge Id
    _)                 = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "AltMerge"
    pprTickType (CaseElim Id
    _)                 = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "CaseElim"
    pprTickType (CaseIdentity Id
    _)             = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "CaseIdentity"
    pprTickType (FillInCaseDefault Id
    _)        = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "FillInCaseDefault"
    pprTickType Tick
    SimplifierDone               = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "SimplifierDone"

    pprTickCts :: Tick -> SDoc
    pprTickCts :: Tick -> SDoc
    pprTickCts (PreInlineUnconditionally Id
    v) = Id -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Id
    v
    pprTickCts (PostInlineUnconditionally Id
    v)= Id -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Id
    v
    pprTickCts (UnfoldingDone Id
    v)            = Id -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Id
    v
    pprTickCts (RuleFired FastString
    v)                = FastString -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr FastString
    v
    pprTickCts Tick
    LetFloatFromLet              = SDoc
    forall doc. IsOutput doc => doc
    Outputable.empty
    pprTickCts (EtaExpansion Id
    v)             = Id -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Id
    v
    pprTickCts (EtaReduction Id
    v)             = Id -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Id
    v
    pprTickCts (BetaReduction Id
    v)            = Id -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Id
    v
    pprTickCts (CaseOfCase Id
    v)               = Id -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Id
    v
    pprTickCts (KnownBranch Id
    v)              = Id -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Id
    v
    pprTickCts (CaseMerge Id
    v)                = Id -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Id
    v
    pprTickCts (AltMerge Id
    v)                 = Id -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Id
    v
    pprTickCts (CaseElim Id
    v)                 = Id -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Id
    v
    pprTickCts (CaseIdentity Id
    v)             = Id -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Id
    v
    pprTickCts (FillInCaseDefault Id
    v)        = Id -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Id
    v
    pprTickCts Tick
    _                            = SDoc
    forall doc. IsOutput doc => doc
    Outputable.empty

    cmpTick :: Tick -> Tick -> Ordering
    cmpTick :: Tick -> Tick -> Ordering
    cmpTick Tick
    a Tick
    b = case (Tick -> Int
    tickToTag Tick
    a Int -> Int -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` Tick -> Int
    tickToTag Tick
    b) of
                    Ordering
    GT -> Ordering
    GT
                    Ordering
    EQ -> Tick -> Tick -> Ordering
    cmpEqTick Tick
    a Tick
    b
                    Ordering
    LT -> Ordering
    LT

    cmpEqTick :: Tick -> Tick -> Ordering
    cmpEqTick :: Tick -> Tick -> Ordering
    cmpEqTick (PreInlineUnconditionally Id
    a)  (PreInlineUnconditionally Id
    b)    = Id
    a Id -> Id -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` Id
    b
    cmpEqTick (PostInlineUnconditionally Id
    a) (PostInlineUnconditionally Id
    b)   = Id
    a Id -> Id -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` Id
    b
    cmpEqTick (UnfoldingDone Id
    a)             (UnfoldingDone Id
    b)               = Id
    a Id -> Id -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` Id
    b
    cmpEqTick (RuleFired FastString
    a)                 (RuleFired FastString
    b)                   = FastString
    a FastString -> FastString -> Ordering
    `uniqCompareFS` FastString
    b
    cmpEqTick (EtaExpansion Id
    a)              (EtaExpansion Id
    b)                = Id
    a Id -> Id -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` Id
    b
    cmpEqTick (EtaReduction Id
    a)              (EtaReduction Id
    b)                = Id
    a Id -> Id -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` Id
    b
    cmpEqTick (BetaReduction Id
    a)             (BetaReduction Id
    b)               = Id
    a Id -> Id -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` Id
    b
    cmpEqTick (CaseOfCase Id
    a)                (CaseOfCase Id
    b)                  = Id
    a Id -> Id -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` Id
    b
    cmpEqTick (KnownBranch Id
    a)               (KnownBranch Id
    b)                 = Id
    a Id -> Id -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` Id
    b
    cmpEqTick (CaseMerge Id
    a)                 (CaseMerge Id
    b)                   = Id
    a Id -> Id -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` Id
    b
    cmpEqTick (AltMerge Id
    a)                  (AltMerge Id
    b)                    = Id
    a Id -> Id -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` Id
    b
    cmpEqTick (CaseElim Id
    a)                  (CaseElim Id
    b)                    = Id
    a Id -> Id -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` Id
    b
    cmpEqTick (CaseIdentity Id
    a)              (CaseIdentity Id
    b)                = Id
    a Id -> Id -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` Id
    b
    cmpEqTick (FillInCaseDefault Id
    a)         (FillInCaseDefault Id
    b)           = Id
    a Id -> Id -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` Id
    b
    cmpEqTick Tick
    _                             Tick
    _                               = Ordering
    EQ