diff options
author | Luite Stegeman <stegeman@gmail.com> | 2021-01-27 11:48:42 +0100 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2021-03-20 07:49:15 -0400 |
commit | 7de3532f0317032f75b76150c5d3a6f76178be04 (patch) | |
tree | b2d75538bde38581bbb5447889e9810f47e51a0f /compiler/GHC | |
parent | 0107f3568d060b4c979aa3740465c4f6ca4c2bba (diff) | |
download | haskell-7de3532f0317032f75b76150c5d3a6f76178be04.tar.gz |
Transfer tickish things to GHC.Types.Tickish
Metric Increase:
MultiLayerModules
Diffstat (limited to 'compiler/GHC')
47 files changed, 420 insertions, 336 deletions
diff --git a/compiler/GHC/Cmm/DebugBlock.hs b/compiler/GHC/Cmm/DebugBlock.hs index 0de3efe044..e6d1f2735e 100644 --- a/compiler/GHC/Cmm/DebugBlock.hs +++ b/compiler/GHC/Cmm/DebugBlock.hs @@ -39,13 +39,13 @@ import GHC.Cmm.BlockId import GHC.Cmm.CLabel import GHC.Cmm import GHC.Cmm.Utils -import GHC.Core import GHC.Data.FastString ( nilFS, mkFastString ) import GHC.Unit.Module import GHC.Utils.Outputable import GHC.Utils.Panic import GHC.Cmm.Ppr.Expr ( pprExpr ) import GHC.Types.SrcLoc +import GHC.Types.Tickish import GHC.Utils.Misc ( seqList ) import GHC.Cmm.Dataflow.Block diff --git a/compiler/GHC/Cmm/Node.hs b/compiler/GHC/Cmm/Node.hs index 37a27fd75f..fe6eac3223 100644 --- a/compiler/GHC/Cmm/Node.hs +++ b/compiler/GHC/Cmm/Node.hs @@ -34,7 +34,7 @@ import GHC.Data.FastString import GHC.Types.ForeignCall import GHC.Utils.Outputable import GHC.Runtime.Heap.Layout -import GHC.Core (CmmTickish) +import GHC.Types.Tickish (CmmTickish) import qualified GHC.Types.Unique as U import GHC.Cmm.Dataflow.Block diff --git a/compiler/GHC/Cmm/Parser.y b/compiler/GHC/Cmm/Parser.y index ceb5ba8bad..8a972b91d5 100644 --- a/compiler/GHC/Cmm/Parser.y +++ b/compiler/GHC/Cmm/Parser.y @@ -224,8 +224,6 @@ import GHC.StgToCmm.Ticky import GHC.StgToCmm.Prof import GHC.StgToCmm.Bind ( emitBlackHoleCode, emitUpdateFrame ) -import GHC.Core ( GenTickish(SourceNote) ) - import GHC.Cmm.Opt import GHC.Cmm.Graph import GHC.Cmm @@ -250,6 +248,7 @@ import GHC.Types.Literal import GHC.Types.Unique import GHC.Types.Unique.FM import GHC.Types.SrcLoc +import GHC.Types.Tickish ( GenTickish(SourceNote) ) import GHC.Driver.Session import GHC.Driver.Ppr import GHC.Driver.Config diff --git a/compiler/GHC/CmmToAsm/Dwarf.hs b/compiler/GHC/CmmToAsm/Dwarf.hs index b79397a998..9b48d25bf4 100644 --- a/compiler/GHC/CmmToAsm/Dwarf.hs +++ b/compiler/GHC/CmmToAsm/Dwarf.hs @@ -7,7 +7,7 @@ import GHC.Prelude import GHC.Cmm.CLabel import GHC.Cmm.Expr ( GlobalReg(..) ) import GHC.Settings.Config ( cProjectName, cProjectVersion ) -import GHC.Core ( CmmTickish, GenTickish(..) ) +import GHC.Types.Tickish ( CmmTickish, GenTickish(..) ) import GHC.Cmm.DebugBlock import GHC.Unit.Module import GHC.Utils.Outputable diff --git a/compiler/GHC/CmmToAsm/PPC/CodeGen.hs b/compiler/GHC/CmmToAsm/PPC/CodeGen.hs index d547412935..1111917de8 100644 --- a/compiler/GHC/CmmToAsm/PPC/CodeGen.hs +++ b/compiler/GHC/CmmToAsm/PPC/CodeGen.hs @@ -57,7 +57,7 @@ import GHC.Cmm.Switch import GHC.Cmm.CLabel import GHC.Cmm.Dataflow.Block import GHC.Cmm.Dataflow.Graph -import GHC.Core ( GenTickish(..) ) +import GHC.Types.Tickish ( GenTickish(..) ) import GHC.Types.SrcLoc ( srcSpanFile, srcSpanStartLine, srcSpanStartCol ) -- The rest: diff --git a/compiler/GHC/CmmToAsm/X86/CodeGen.hs b/compiler/GHC/CmmToAsm/X86/CodeGen.hs index 7699b0c692..878f3387fb 100644 --- a/compiler/GHC/CmmToAsm/X86/CodeGen.hs +++ b/compiler/GHC/CmmToAsm/X86/CodeGen.hs @@ -72,7 +72,7 @@ import GHC.Cmm.Dataflow.Collections import GHC.Cmm.Dataflow.Graph import GHC.Cmm.Dataflow.Label import GHC.Cmm.CLabel -import GHC.Core ( GenTickish(..) ) +import GHC.Types.Tickish ( GenTickish(..) ) import GHC.Types.SrcLoc ( srcSpanFile, srcSpanStartLine, srcSpanStartCol ) -- The rest: diff --git a/compiler/GHC/Core.hs b/compiler/GHC/Core.hs index e00986566d..2c30b6f3d4 100644 --- a/compiler/GHC/Core.hs +++ b/compiler/GHC/Core.hs @@ -6,11 +6,6 @@ {-# LANGUAGE CPP, DeriveDataTypeable, FlexibleContexts #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE BangPatterns #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE FlexibleInstances #-} - {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} {-# OPTIONS_GHC -Wno-incomplete-record-updates #-} @@ -19,8 +14,6 @@ module GHC.Core ( -- * Main data types Expr(..), Alt(..), Bind(..), AltCon(..), Arg, - GenTickish(..), CoreTickish, StgTickish, CmmTickish, XTickishId, - TickishScoping(..), TickishPlacement(..), CoreProgram, CoreExpr, CoreAlt, CoreBind, CoreArg, CoreBndr, TaggedExpr, TaggedAlt, TaggedBind, TaggedArg, TaggedBndr(..), deTagExpr, @@ -59,12 +52,6 @@ module GHC.Core ( isValArg, isTypeArg, isCoArg, isTyCoArg, valArgCount, valBndrCount, isRuntimeArg, isRuntimeVar, - -- * Tick-related functions - tickishCounts, tickishScoped, tickishScopesLike, tickishFloatable, - tickishCanSplit, mkNoCount, mkNoScope, - tickishIsCode, tickishPlace, - tickishContains, - -- * Unfolding data types Unfolding(..), UnfoldingGuidance(..), UnfoldingSource(..), @@ -110,7 +97,6 @@ module GHC.Core ( import GHC.Prelude import GHC.Platform -import GHC.Types.CostCentre import GHC.Types.Var.Env( InScopeSet ) import GHC.Types.Var import GHC.Core.Type @@ -119,11 +105,11 @@ import GHC.Types.Name import GHC.Types.Name.Set import GHC.Types.Name.Env( NameEnv, emptyNameEnv ) import GHC.Types.Literal +import GHC.Types.Tickish import GHC.Core.DataCon import GHC.Unit.Module import GHC.Types.Basic import GHC.Types.Unique.Set -import GHC.Types.SrcLoc ( RealSrcSpan, containsSpan ) import GHC.Utils.Binary import GHC.Utils.Misc @@ -132,8 +118,6 @@ import GHC.Utils.Panic import GHC.Driver.Ppr -import Language.Haskell.Syntax.Extension ( NoExtField ) - import Data.Data hiding (TyCon) import Data.Int import Data.Word @@ -941,313 +925,6 @@ type OutArg = CoreArg type MOutCoercion = MCoercion -{- ********************************************************************* -* * - Ticks -* * -************************************************************************ --} - --- | Allows attaching extra information to points in expressions - --- | Used as a data type index for the GenTickish annotations -data TickishPass - = TickishCore - | TickishStg - | TickishCmm - -type family XBreakpoint (pass :: TickishPass) -type instance XBreakpoint 'TickishCore = NoExtField --- | Keep track of the type of breakpoints in STG, for GHCi -type instance XBreakpoint 'TickishStg = Type -type instance XBreakpoint 'TickishCmm = NoExtField - -type family XTickishId (pass :: TickishPass) -type instance XTickishId 'TickishCore = Id -type instance XTickishId 'TickishStg = Id -type instance XTickishId 'TickishCmm = NoExtField - -type CoreTickish = GenTickish 'TickishCore -type StgTickish = GenTickish 'TickishStg --- | Tickish in Cmm context (annotations only) -type CmmTickish = GenTickish 'TickishCmm - --- If you edit this type, you may need to update the GHC formalism --- See Note [GHC Formalism] in GHC.Core.Lint -data GenTickish pass = - -- | An @{-# SCC #-}@ profiling annotation, either automatically - -- added by the desugarer as a result of -auto-all, or added by - -- the user. - ProfNote { - profNoteCC :: CostCentre, -- ^ the cost centre - profNoteCount :: !Bool, -- ^ bump the entry count? - profNoteScope :: !Bool -- ^ scopes over the enclosed expression - -- (i.e. not just a tick) - } - - -- | A "tick" used by HPC to track the execution of each - -- subexpression in the original source code. - | HpcTick { - tickModule :: Module, - tickId :: !Int - } - - -- | A breakpoint for the GHCi debugger. This behaves like an HPC - -- tick, but has a list of free variables which will be available - -- for inspection in GHCi when the program stops at the breakpoint. - -- - -- NB. we must take account of these Ids when (a) counting free variables, - -- and (b) substituting (don't substitute for them) - | Breakpoint - { breakpointExt :: XBreakpoint pass - , breakpointId :: !Int - , breakpointFVs :: [XTickishId pass] - -- ^ the order of this list is important: - -- it matches the order of the lists in the - -- appropriate entry in 'GHC.ByteCode.Types.ModBreaks'. - -- - -- Careful about substitution! See - -- Note [substTickish] in "GHC.Core.Subst". - } - - -- | A source note. - -- - -- Source notes are pure annotations: Their presence should neither - -- influence compilation nor execution. The semantics are given by - -- causality: The presence of a source note means that a local - -- change in the referenced source code span will possibly provoke - -- the generated code to change. On the flip-side, the functionality - -- of annotated code *must* be invariant against changes to all - -- source code *except* the spans referenced in the source notes - -- (see "Causality of optimized Haskell" paper for details). - -- - -- Therefore extending the scope of any given source note is always - -- valid. Note that it is still undesirable though, as this reduces - -- their usefulness for debugging and profiling. Therefore we will - -- generally try only to make use of this property where it is - -- necessary to enable optimizations. - | SourceNote - { sourceSpan :: RealSrcSpan -- ^ Source covered - , sourceName :: String -- ^ Name for source location - -- (uses same names as CCs) - } - -deriving instance Eq (GenTickish 'TickishCore) -deriving instance Ord (GenTickish 'TickishCore) -deriving instance Data (GenTickish 'TickishCore) - -deriving instance Data (GenTickish 'TickishStg) - -deriving instance Eq (GenTickish 'TickishCmm) -deriving instance Ord (GenTickish 'TickishCmm) -deriving instance Data (GenTickish 'TickishCmm) - - --- | A "counting tick" (where tickishCounts is True) is one that --- counts evaluations in some way. We cannot discard a counting tick, --- and the compiler should preserve the number of counting ticks as --- far as possible. --- --- However, we still allow the simplifier to increase or decrease --- sharing, so in practice the actual number of ticks may vary, except --- that we never change the value from zero to non-zero or vice versa. -tickishCounts :: GenTickish pass -> Bool -tickishCounts n@ProfNote{} = profNoteCount n -tickishCounts HpcTick{} = True -tickishCounts Breakpoint{} = True -tickishCounts _ = False - - --- | Specifies the scoping behaviour of ticks. This governs the --- behaviour of ticks that care about the covered code and the cost --- associated with it. Important for ticks relating to profiling. -data TickishScoping = - -- | No scoping: The tick does not care about what code it - -- covers. Transformations can freely move code inside as well as - -- outside without any additional annotation obligations - NoScope - - -- | Soft scoping: We want all code that is covered to stay - -- covered. Note that this scope type does not forbid - -- transformations from happening, as long as all results of - -- the transformations are still covered by this tick or a copy of - -- it. For example - -- - -- let x = tick<...> (let y = foo in bar) in baz - -- ===> - -- let x = tick<...> bar; y = tick<...> foo in baz - -- - -- Is a valid transformation as far as "bar" and "foo" is - -- concerned, because both still are scoped over by the tick. - -- - -- Note though that one might object to the "let" not being - -- covered by the tick any more. However, we are generally lax - -- with this - constant costs don't matter too much, and given - -- that the "let" was effectively merged we can view it as having - -- lost its identity anyway. - -- - -- Also note that this scoping behaviour allows floating a tick - -- "upwards" in pretty much any situation. For example: - -- - -- case foo of x -> tick<...> bar - -- ==> - -- tick<...> case foo of x -> bar - -- - -- While this is always legal, we want to make a best effort to - -- only make us of this where it exposes transformation - -- opportunities. - | SoftScope - - -- | Cost centre scoping: We don't want any costs to move to other - -- cost-centre stacks. This means we not only want no code or cost - -- to get moved out of their cost centres, but we also object to - -- code getting associated with new cost-centre ticks - or - -- changing the order in which they get applied. - -- - -- A rule of thumb is that we don't want any code to gain new - -- annotations. However, there are notable exceptions, for - -- example: - -- - -- let f = \y -> foo in tick<...> ... (f x) ... - -- ==> - -- tick<...> ... foo[x/y] ... - -- - -- In-lining lambdas like this is always legal, because inlining a - -- function does not change the cost-centre stack when the - -- function is called. - | CostCentreScope - - deriving (Eq) - --- | Returns the intended scoping rule for a Tickish -tickishScoped :: GenTickish pass -> TickishScoping -tickishScoped n@ProfNote{} - | profNoteScope n = CostCentreScope - | otherwise = NoScope -tickishScoped HpcTick{} = NoScope -tickishScoped Breakpoint{} = CostCentreScope - -- Breakpoints are scoped: eventually we're going to do call - -- stacks, but also this helps prevent the simplifier from moving - -- breakpoints around and changing their result type (see #1531). -tickishScoped SourceNote{} = SoftScope - --- | Returns whether the tick scoping rule is at least as permissive --- as the given scoping rule. -tickishScopesLike :: GenTickish pass -> TickishScoping -> Bool -tickishScopesLike t scope = tickishScoped t `like` scope - where NoScope `like` _ = True - _ `like` NoScope = False - SoftScope `like` _ = True - _ `like` SoftScope = False - CostCentreScope `like` _ = True - --- | Returns @True@ for ticks that can be floated upwards easily even --- where it might change execution counts, such as: --- --- Just (tick<...> foo) --- ==> --- tick<...> (Just foo) --- --- This is a combination of @tickishSoftScope@ and --- @tickishCounts@. Note that in principle splittable ticks can become --- floatable using @mkNoTick@ -- even though there's currently no --- tickish for which that is the case. -tickishFloatable :: GenTickish pass -> Bool -tickishFloatable t = t `tickishScopesLike` SoftScope && not (tickishCounts t) - --- | Returns @True@ for a tick that is both counting /and/ scoping and --- can be split into its (tick, scope) parts using 'mkNoScope' and --- 'mkNoTick' respectively. -tickishCanSplit :: GenTickish pass -> Bool -tickishCanSplit ProfNote{profNoteScope = True, profNoteCount = True} - = True -tickishCanSplit _ = False - -mkNoCount :: GenTickish pass -> GenTickish pass -mkNoCount n | not (tickishCounts n) = n - | not (tickishCanSplit n) = panic "mkNoCount: Cannot split!" -mkNoCount n@ProfNote{} = n {profNoteCount = False} -mkNoCount _ = panic "mkNoCount: Undefined split!" - -mkNoScope :: GenTickish pass -> GenTickish pass -mkNoScope n | tickishScoped n == NoScope = n - | not (tickishCanSplit n) = panic "mkNoScope: Cannot split!" -mkNoScope n@ProfNote{} = n {profNoteScope = False} -mkNoScope _ = panic "mkNoScope: Undefined split!" - --- | Return @True@ if this source annotation compiles to some backend --- code. Without this flag, the tickish is seen as a simple annotation --- that does not have any associated evaluation code. --- --- What this means that we are allowed to disregard the tick if doing --- so means that we can skip generating any code in the first place. A --- typical example is top-level bindings: --- --- foo = tick<...> \y -> ... --- ==> --- foo = \y -> tick<...> ... --- --- Here there is just no operational difference between the first and --- the second version. Therefore code generation should simply --- translate the code as if it found the latter. -tickishIsCode :: GenTickish pass -> Bool -tickishIsCode SourceNote{} = False -tickishIsCode _tickish = True -- all the rest for now - - --- | Governs the kind of expression that the tick gets placed on when --- annotating for example using @mkTick@. If we find that we want to --- put a tickish on an expression ruled out here, we try to float it --- inwards until we find a suitable expression. -data TickishPlacement = - - -- | Place ticks exactly on run-time expressions. We can still - -- move the tick through pure compile-time constructs such as - -- other ticks, casts or type lambdas. This is the most - -- restrictive placement rule for ticks, as all tickishs have in - -- common that they want to track runtime processes. The only - -- legal placement rule for counting ticks. - PlaceRuntime - - -- | As @PlaceRuntime@, but we float the tick through all - -- lambdas. This makes sense where there is little difference - -- between annotating the lambda and annotating the lambda's code. - | PlaceNonLam - - -- | In addition to floating through lambdas, cost-centre style - -- tickishs can also be moved from constructors, non-function - -- variables and literals. For example: - -- - -- let x = scc<...> C (scc<...> y) (scc<...> 3) in ... - -- - -- Neither the constructor application, the variable or the - -- literal are likely to have any cost worth mentioning. And even - -- if y names a thunk, the call would not care about the - -- evaluation context. Therefore removing all annotations in the - -- above example is safe. - | PlaceCostCentre - - deriving (Eq) - --- | Placement behaviour we want for the ticks -tickishPlace :: GenTickish pass -> TickishPlacement -tickishPlace n@ProfNote{} - | profNoteCount n = PlaceRuntime - | otherwise = PlaceCostCentre -tickishPlace HpcTick{} = PlaceRuntime -tickishPlace Breakpoint{} = PlaceRuntime -tickishPlace SourceNote{} = PlaceNonLam - --- | Returns whether one tick "contains" the other one, therefore --- making the second tick redundant. -tickishContains :: Eq (GenTickish pass) - => GenTickish pass -> GenTickish pass -> Bool -tickishContains (SourceNote sp1 n1) (SourceNote sp2 n2) - = containsSpan sp1 sp2 && n1 == n2 - -- compare the String last -tickishContains t1 t2 - = t1 == t2 - {- ************************************************************************ * * diff --git a/compiler/GHC/Core/FVs.hs b/compiler/GHC/Core/FVs.hs index c1b4a49bbb..cef3dc3cbe 100644 --- a/compiler/GHC/Core/FVs.hs +++ b/compiler/GHC/Core/FVs.hs @@ -65,6 +65,7 @@ import GHC.Types.Id import GHC.Types.Id.Info import GHC.Types.Name.Set import GHC.Types.Name +import GHC.Types.Tickish import GHC.Types.Var.Set import GHC.Types.Var import GHC.Core.Type diff --git a/compiler/GHC/Core/Lint.hs b/compiler/GHC/Core/Lint.hs index f3c69defef..7edc0d7a28 100644 --- a/compiler/GHC/Core/Lint.hs +++ b/compiler/GHC/Core/Lint.hs @@ -53,6 +53,7 @@ import GHC.Types.Id.Info import GHC.Core.Ppr import GHC.Core.Coercion import GHC.Types.SrcLoc +import GHC.Types.Tickish import GHC.Core.Type as Type import GHC.Core.Multiplicity import GHC.Core.UsageEnv diff --git a/compiler/GHC/Core/Map/Expr.hs b/compiler/GHC/Core/Map/Expr.hs index 04c786deec..30be6adea2 100644 --- a/compiler/GHC/Core/Map/Expr.hs +++ b/compiler/GHC/Core/Map/Expr.hs @@ -32,6 +32,7 @@ import GHC.Data.TrieMap import GHC.Core.Map.Type import GHC.Core import GHC.Core.Type +import GHC.Types.Tickish import GHC.Types.Var import GHC.Utils.Misc diff --git a/compiler/GHC/Core/Opt/Arity.hs b/compiler/GHC/Core/Opt/Arity.hs index 6dd1148e56..ec450ec245 100644 --- a/compiler/GHC/Core/Opt/Arity.hs +++ b/compiler/GHC/Core/Opt/Arity.hs @@ -58,6 +58,7 @@ import GHC.Core.Predicate ( isDictTy ) import GHC.Core.Multiplicity import GHC.Types.Var.Set import GHC.Types.Basic +import GHC.Types.Tickish import GHC.Builtin.Uniques import GHC.Driver.Session ( DynFlags, GeneralFlag(..), gopt ) import GHC.Utils.Outputable diff --git a/compiler/GHC/Core/Opt/CSE.hs b/compiler/GHC/Core/Opt/CSE.hs index 9e3010ca47..4e5f511109 100644 --- a/compiler/GHC/Core/Opt/CSE.hs +++ b/compiler/GHC/Core/Opt/CSE.hs @@ -30,6 +30,7 @@ import GHC.Core.Type ( tyConAppArgs ) import GHC.Core import GHC.Utils.Outputable import GHC.Types.Basic +import GHC.Types.Tickish import GHC.Core.Map.Expr import GHC.Utils.Misc ( filterOut, equalLength, debugIsOn ) import GHC.Utils.Panic diff --git a/compiler/GHC/Core/Opt/CallerCC.hs b/compiler/GHC/Core/Opt/CallerCC.hs index 68875dc18f..aeffe2c034 100644 --- a/compiler/GHC/Core/Opt/CallerCC.hs +++ b/compiler/GHC/Core/Opt/CallerCC.hs @@ -31,6 +31,7 @@ import GHC.Driver.Ppr import GHC.Types.CostCentre import GHC.Types.CostCentre.State import GHC.Types.Name hiding (varName) +import GHC.Types.Tickish import GHC.Unit.Module.Name import GHC.Unit.Module.ModGuts import GHC.Types.SrcLoc diff --git a/compiler/GHC/Core/Opt/ConstantFold.hs b/compiler/GHC/Core/Opt/ConstantFold.hs index c463bda314..c34996b507 100644 --- a/compiler/GHC/Core/Opt/ConstantFold.hs +++ b/compiler/GHC/Core/Opt/ConstantFold.hs @@ -60,6 +60,7 @@ import GHC.Core.Type import GHC.Types.Var.Set import GHC.Types.Var.Env import GHC.Types.Name.Occurrence ( occNameFS ) +import GHC.Types.Tickish import GHC.Builtin.Names import GHC.Data.Maybe ( orElse ) import GHC.Types.Name ( Name, nameOccName ) diff --git a/compiler/GHC/Core/Opt/FloatIn.hs b/compiler/GHC/Core/Opt/FloatIn.hs index 7feea9f516..0f2eb85f73 100644 --- a/compiler/GHC/Core/Opt/FloatIn.hs +++ b/compiler/GHC/Core/Opt/FloatIn.hs @@ -34,6 +34,7 @@ import GHC.Core.Type import GHC.Types.Basic ( RecFlag(..), isRec ) import GHC.Types.Id ( isOneShotBndr, idType, isJoinId, isJoinId_maybe ) +import GHC.Types.Tickish import GHC.Types.Var import GHC.Types.Var.Set diff --git a/compiler/GHC/Core/Opt/FloatOut.hs b/compiler/GHC/Core/Opt/FloatOut.hs index d0a544c020..ed6c3759c1 100644 --- a/compiler/GHC/Core/Opt/FloatOut.hs +++ b/compiler/GHC/Core/Opt/FloatOut.hs @@ -22,6 +22,7 @@ import GHC.Driver.Session import GHC.Utils.Logger ( dumpIfSet_dyn, DumpFormat (..), Logger ) import GHC.Types.Id ( Id, idArity, idType, isDeadEndId, isJoinId, isJoinId_maybe ) +import GHC.Types.Tickish import GHC.Core.Opt.SetLevels import GHC.Types.Unique.Supply ( UniqSupply ) import GHC.Data.Bag diff --git a/compiler/GHC/Core/Opt/OccurAnal.hs b/compiler/GHC/Core/Opt/OccurAnal.hs index 32853b6aff..d8796caa6e 100644 --- a/compiler/GHC/Core/Opt/OccurAnal.hs +++ b/compiler/GHC/Core/Opt/OccurAnal.hs @@ -33,6 +33,7 @@ import GHC.Core.Opt.Arity ( joinRhsArity ) import GHC.Types.Id import GHC.Types.Id.Info import GHC.Types.Basic +import GHC.Types.Tickish import GHC.Unit.Module( Module ) import GHC.Core.Coercion import GHC.Core.Type diff --git a/compiler/GHC/Core/Opt/Pipeline.hs b/compiler/GHC/Core/Opt/Pipeline.hs index 0493ad911a..d3dcfb3263 100644 --- a/compiler/GHC/Core/Opt/Pipeline.hs +++ b/compiler/GHC/Core/Opt/Pipeline.hs @@ -70,6 +70,7 @@ import GHC.Types.Basic import GHC.Types.Demand ( zapDmdEnvSig ) import GHC.Types.Var.Set import GHC.Types.Var.Env +import GHC.Types.Tickish import GHC.Types.Unique.Supply ( UniqSupply ) import GHC.Types.Unique.FM import GHC.Types.Name.Ppr diff --git a/compiler/GHC/Core/Opt/SetLevels.hs b/compiler/GHC/Core/Opt/SetLevels.hs index 88b1d34a9e..2ea0c8606d 100644 --- a/compiler/GHC/Core/Opt/SetLevels.hs +++ b/compiler/GHC/Core/Opt/SetLevels.hs @@ -108,6 +108,7 @@ import GHC.Types.Cpr ( mkCprSig, botCpr ) import GHC.Types.Name ( getOccName, mkSystemVarName ) import GHC.Types.Name.Occurrence ( occNameString ) import GHC.Types.Unique ( hasKey ) +import GHC.Types.Tickish ( tickishIsCode ) import GHC.Core.Type ( Type, splitTyConApp_maybe, tyCoVarsOfType , mightBeUnliftedType, closeOverKindsDSet ) import GHC.Core.Multiplicity ( pattern Many ) diff --git a/compiler/GHC/Core/Opt/Simplify.hs b/compiler/GHC/Core/Opt/Simplify.hs index 8090ddb369..c531da6050 100644 --- a/compiler/GHC/Core/Opt/Simplify.hs +++ b/compiler/GHC/Core/Opt/Simplify.hs @@ -59,6 +59,7 @@ import GHC.Core.Rules ( lookupRule, getRules, initRuleOpts ) import GHC.Types.Basic import GHC.Utils.Monad ( mapAccumLM, liftIO ) import GHC.Utils.Logger +import GHC.Types.Tickish import GHC.Types.Var ( isTyCoVar ) import GHC.Data.Maybe ( orElse ) import Control.Monad diff --git a/compiler/GHC/Core/Opt/Simplify/Utils.hs b/compiler/GHC/Core/Opt/Simplify/Utils.hs index ec83c25cc4..672b0bce72 100644 --- a/compiler/GHC/Core/Opt/Simplify/Utils.hs +++ b/compiler/GHC/Core/Opt/Simplify/Utils.hs @@ -57,6 +57,7 @@ import GHC.Core.Unfold.Make import GHC.Types.Name import GHC.Types.Id import GHC.Types.Id.Info +import GHC.Types.Tickish import GHC.Types.Var import GHC.Types.Demand import GHC.Types.Var.Set diff --git a/compiler/GHC/Core/Opt/SpecConstr.hs b/compiler/GHC/Core/Opt/SpecConstr.hs index 8ffe04ab25..1e00e4cc21 100644 --- a/compiler/GHC/Core/Opt/SpecConstr.hs +++ b/compiler/GHC/Core/Opt/SpecConstr.hs @@ -44,6 +44,7 @@ import GHC.Core.Make ( mkImpossibleExpr ) import GHC.Types.Var.Env import GHC.Types.Var.Set import GHC.Types.Name +import GHC.Types.Tickish import GHC.Types.Basic import GHC.Driver.Session ( DynFlags(..), GeneralFlag( Opt_SpecConstrKeen ) , gopt, hasPprDebug ) diff --git a/compiler/GHC/Core/Opt/Specialise.hs b/compiler/GHC/Core/Opt/Specialise.hs index c18785cee1..cab33d8de7 100644 --- a/compiler/GHC/Core/Opt/Specialise.hs +++ b/compiler/GHC/Core/Opt/Specialise.hs @@ -47,6 +47,7 @@ import GHC.Types.Basic import GHC.Types.Unique.Supply import GHC.Types.Unique.DFM import GHC.Types.Name +import GHC.Types.Tickish import GHC.Types.Id.Make ( voidArgId, voidPrimId ) import GHC.Types.Var ( isLocalVar ) import GHC.Types.Var.Set diff --git a/compiler/GHC/Core/Ppr.hs b/compiler/GHC/Core/Ppr.hs index 04e51aacde..a55b545b0a 100644 --- a/compiler/GHC/Core/Ppr.hs +++ b/compiler/GHC/Core/Ppr.hs @@ -46,6 +46,7 @@ import GHC.Utils.Misc import GHC.Utils.Outputable import GHC.Data.FastString import GHC.Types.SrcLoc ( pprUserRealSpan ) +import GHC.Types.Tickish {- ************************************************************************ diff --git a/compiler/GHC/Core/Rules.hs b/compiler/GHC/Core/Rules.hs index f29d700719..41cab2d201 100644 --- a/compiler/GHC/Core/Rules.hs +++ b/compiler/GHC/Core/Rules.hs @@ -58,6 +58,7 @@ import GHC.Types.Name ( Name, NamedThing(..), nameIsLocalOrFrom ) import GHC.Types.Name.Set import GHC.Types.Name.Env import GHC.Types.Unique.FM +import GHC.Types.Tickish import GHC.Core.Unify as Unify ( ruleMatchTyKiX ) import GHC.Types.Basic import GHC.Driver.Session ( DynFlags, gopt, targetPlatform, homeUnitId_ ) diff --git a/compiler/GHC/Core/Seq.hs b/compiler/GHC/Core/Seq.hs index 35a87aab9a..6dfbfef768 100644 --- a/compiler/GHC/Core/Seq.hs +++ b/compiler/GHC/Core/Seq.hs @@ -17,6 +17,7 @@ import GHC.Types.Id.Info import GHC.Types.Demand( seqDemand, seqStrictSig ) import GHC.Types.Cpr( seqCprSig ) import GHC.Types.Basic( seqOccInfo ) +import GHC.Types.Tickish import GHC.Types.Var.Set( seqDVarSet ) import GHC.Types.Var( varType, tyVarKind ) import GHC.Core.Type( seqType, isTyVar ) diff --git a/compiler/GHC/Core/SimpleOpt.hs b/compiler/GHC/Core/SimpleOpt.hs index 519638d25d..90cd3f039e 100644 --- a/compiler/GHC/Core/SimpleOpt.hs +++ b/compiler/GHC/Core/SimpleOpt.hs @@ -41,6 +41,7 @@ import GHC.Types.Var.Set import GHC.Types.Var.Env import GHC.Core.DataCon import GHC.Types.Demand( etaConvertStrictSig ) +import GHC.Types.Tickish import GHC.Core.Coercion.Opt ( optCoercion, OptCoercionOpts (..) ) import GHC.Core.Type hiding ( substTy, extendTvSubst, extendCvSubst, extendTvSubstList , isInScope, substTyVarBndr, cloneTyVarBndr ) diff --git a/compiler/GHC/Core/Stats.hs b/compiler/GHC/Core/Stats.hs index e43e4e4471..04e6bc3274 100644 --- a/compiler/GHC/Core/Stats.hs +++ b/compiler/GHC/Core/Stats.hs @@ -17,6 +17,7 @@ import GHC.Types.Basic import GHC.Core import GHC.Utils.Outputable import GHC.Core.Coercion +import GHC.Types.Tickish import GHC.Types.Var import GHC.Core.Type(Type, typeSize) import GHC.Types.Id (isJoinId) diff --git a/compiler/GHC/Core/Subst.hs b/compiler/GHC/Core/Subst.hs index 3ed3996488..520bfd5d16 100644 --- a/compiler/GHC/Core/Subst.hs +++ b/compiler/GHC/Core/Subst.hs @@ -60,6 +60,7 @@ import GHC.Types.Var.Env import GHC.Types.Id import GHC.Types.Name ( Name ) import GHC.Types.Var +import GHC.Types.Tickish import GHC.Types.Id.Info import GHC.Types.Unique.Supply import GHC.Data.Maybe diff --git a/compiler/GHC/Core/Tidy.hs b/compiler/GHC/Core/Tidy.hs index c88cbdc0c4..61f98e20a4 100644 --- a/compiler/GHC/Core/Tidy.hs +++ b/compiler/GHC/Core/Tidy.hs @@ -30,6 +30,7 @@ import GHC.Types.Unique (getUnique) import GHC.Types.Unique.FM import GHC.Types.Name hiding (tidyNameOcc) import GHC.Types.SrcLoc +import GHC.Types.Tickish import GHC.Data.Maybe import Data.List (mapAccumL) diff --git a/compiler/GHC/Core/Unfold.hs b/compiler/GHC/Core/Unfold.hs index 1bf641e12f..8fdbc1b891 100644 --- a/compiler/GHC/Core/Unfold.hs +++ b/compiler/GHC/Core/Unfold.hs @@ -61,6 +61,7 @@ import GHC.Utils.Misc import GHC.Utils.Outputable import GHC.Types.ForeignCall import GHC.Types.Name +import GHC.Types.Tickish import qualified Data.ByteString as BS import Data.List (isPrefixOf) diff --git a/compiler/GHC/Core/Utils.hs b/compiler/GHC/Core/Utils.hs index 5a4b6304f1..3f228f747d 100644 --- a/compiler/GHC/Core/Utils.hs +++ b/compiler/GHC/Core/Utils.hs @@ -83,6 +83,7 @@ import GHC.Types.Var.Env import GHC.Types.Var.Set import GHC.Types.Name import GHC.Types.Literal +import GHC.Types.Tickish import GHC.Core.DataCon import GHC.Builtin.PrimOps import GHC.Types.Id diff --git a/compiler/GHC/CoreToByteCode.hs b/compiler/GHC/CoreToByteCode.hs index 23bb018806..dbb64d51d5 100644 --- a/compiler/GHC/CoreToByteCode.hs +++ b/compiler/GHC/CoreToByteCode.hs @@ -65,6 +65,7 @@ import GHC.Data.OrdList import GHC.Data.Maybe import GHC.Types.Var.Env import GHC.Builtin.Names ( unsafeEqualityProofName ) +import GHC.Types.Tickish import Data.List ( genericReplicate, genericLength, intersperse , partition, scanl', sort, sortBy, zip4, zip6, nub ) diff --git a/compiler/GHC/CoreToIface.hs b/compiler/GHC/CoreToIface.hs index 48729ea00c..a4587d58ee 100644 --- a/compiler/GHC/CoreToIface.hs +++ b/compiler/GHC/CoreToIface.hs @@ -73,6 +73,7 @@ import GHC.Utils.Misc import GHC.Types.Var import GHC.Types.Var.Env import GHC.Types.Var.Set +import GHC.Types.Tickish import GHC.Core.TyCo.Rep import GHC.Core.TyCo.Tidy ( tidyCo ) import GHC.Types.Demand ( isTopSig ) diff --git a/compiler/GHC/CoreToStg.hs b/compiler/GHC/CoreToStg.hs index 298288d45b..b1397fe4e1 100644 --- a/compiler/GHC/CoreToStg.hs +++ b/compiler/GHC/CoreToStg.hs @@ -32,6 +32,7 @@ import GHC.Types.Id import GHC.Types.Id.Info import GHC.Core.DataCon import GHC.Types.CostCentre +import GHC.Types.Tickish import GHC.Types.Var.Env import GHC.Unit.Module import GHC.Types.Name ( isExternalName, nameModule_maybe ) diff --git a/compiler/GHC/CoreToStg/Prep.hs b/compiler/GHC/CoreToStg/Prep.hs index 02b5505d30..956175b3ad 100644 --- a/compiler/GHC/CoreToStg/Prep.hs +++ b/compiler/GHC/CoreToStg/Prep.hs @@ -72,6 +72,7 @@ import GHC.Types.Basic import GHC.Types.Name ( NamedThing(..), nameSrcSpan, isInternalName ) import GHC.Types.SrcLoc ( SrcSpan(..), realSrcLocSpan, mkRealSrcLoc ) import GHC.Types.Literal +import GHC.Types.Tickish import GHC.Types.TyThing import GHC.Types.CostCentre ( CostCentre, ccFromThisModule ) import GHC.Types.Unique.Supply diff --git a/compiler/GHC/HsToCore/Coverage.hs b/compiler/GHC/HsToCore/Coverage.hs index caeea519aa..c3df228778 100644 --- a/compiler/GHC/HsToCore/Coverage.hs +++ b/compiler/GHC/HsToCore/Coverage.hs @@ -27,7 +27,6 @@ import GHC.Unit import GHC.Cmm.CLabel import GHC.Core.Type -import GHC.Core import GHC.Core.TyCon import GHC.Data.Maybe @@ -50,6 +49,7 @@ import GHC.Types.HpcInfo import GHC.Types.CostCentre import GHC.Types.CostCentre.State import GHC.Types.ForeignStubs +import GHC.Types.Tickish import Control.Monad import Data.List (isSuffixOf, intersperse) diff --git a/compiler/GHC/HsToCore/Expr.hs b/compiler/GHC/HsToCore/Expr.hs index 1b18176051..8bcebb8a51 100644 --- a/compiler/GHC/HsToCore/Expr.hs +++ b/compiler/GHC/HsToCore/Expr.hs @@ -64,6 +64,7 @@ import GHC.Builtin.Names import GHC.Types.Basic import GHC.Data.Maybe import GHC.Types.SrcLoc +import GHC.Types.Tickish import GHC.Utils.Misc import GHC.Data.Bag import GHC.Utils.Outputable as Outputable diff --git a/compiler/GHC/HsToCore/Utils.hs b/compiler/GHC/HsToCore/Utils.hs index 817c69c184..75dab7680f 100644 --- a/compiler/GHC/HsToCore/Utils.hs +++ b/compiler/GHC/HsToCore/Utils.hs @@ -79,6 +79,7 @@ import GHC.Types.Name( isInternalName ) import GHC.Utils.Outputable import GHC.Utils.Panic import GHC.Types.SrcLoc +import GHC.Types.Tickish import GHC.Utils.Misc import GHC.Driver.Session import GHC.Driver.Ppr diff --git a/compiler/GHC/Iface/Tidy.hs b/compiler/GHC/Iface/Tidy.hs index f4e681420c..76ad3c2a79 100644 --- a/compiler/GHC/Iface/Tidy.hs +++ b/compiler/GHC/Iface/Tidy.hs @@ -69,6 +69,7 @@ import GHC.Types.Name.Cache import GHC.Types.Name.Ppr import GHC.Types.Avail import GHC.Types.Unique.Supply +import GHC.Types.Tickish import GHC.Types.TypeEnv import GHC.Unit.Module diff --git a/compiler/GHC/IfaceToCore.hs b/compiler/GHC/IfaceToCore.hs index e7123a8add..ee604d8436 100644 --- a/compiler/GHC/IfaceToCore.hs +++ b/compiler/GHC/IfaceToCore.hs @@ -100,6 +100,7 @@ import GHC.Types.Name.Set import GHC.Types.Id import GHC.Types.Id.Make import GHC.Types.Id.Info +import GHC.Types.Tickish import GHC.Types.TyThing import GHC.Fingerprint diff --git a/compiler/GHC/Stg/FVs.hs b/compiler/GHC/Stg/FVs.hs index a3d8686507..62053001a6 100644 --- a/compiler/GHC/Stg/FVs.hs +++ b/compiler/GHC/Stg/FVs.hs @@ -49,7 +49,7 @@ import GHC.Prelude import GHC.Stg.Syntax import GHC.Types.Id import GHC.Types.Var.Set -import GHC.Core ( GenTickish(Breakpoint) ) +import GHC.Types.Tickish ( GenTickish(Breakpoint) ) import GHC.Utils.Misc import Data.Maybe ( mapMaybe ) diff --git a/compiler/GHC/Stg/Syntax.hs b/compiler/GHC/Stg/Syntax.hs index 72d6760f6f..03ba9b5549 100644 --- a/compiler/GHC/Stg/Syntax.hs +++ b/compiler/GHC/Stg/Syntax.hs @@ -68,7 +68,7 @@ module GHC.Stg.Syntax ( import GHC.Prelude -import GHC.Core ( AltCon, StgTickish ) +import GHC.Core ( AltCon ) import GHC.Types.CostCentre ( CostCentreStack ) import Data.ByteString ( ByteString ) import Data.Data ( Data ) @@ -78,6 +78,7 @@ import GHC.Driver.Session import GHC.Types.ForeignCall ( ForeignCall ) import GHC.Types.Id import GHC.Types.Name ( isDynLinkName ) +import GHC.Types.Tickish ( StgTickish ) import GHC.Types.Var.Set import GHC.Types.Literal ( Literal, literalType ) import GHC.Unit.Module ( Module ) diff --git a/compiler/GHC/StgToCmm/Bind.hs b/compiler/GHC/StgToCmm/Bind.hs index c4d2174d13..f1346d2846 100644 --- a/compiler/GHC/StgToCmm/Bind.hs +++ b/compiler/GHC/StgToCmm/Bind.hs @@ -32,7 +32,7 @@ import GHC.StgToCmm.Closure import GHC.StgToCmm.Foreign (emitPrimCall) import GHC.Cmm.Graph -import GHC.Core ( AltCon(..), tickishIsCode ) +import GHC.Core ( AltCon(..) ) import GHC.Cmm.BlockId import GHC.Runtime.Heap.Layout import GHC.Cmm @@ -49,6 +49,7 @@ import GHC.Data.List.SetOps import GHC.Utils.Misc import GHC.Types.Var.Set import GHC.Types.Basic +import GHC.Types.Tickish ( tickishIsCode ) import GHC.Utils.Outputable import GHC.Utils.Panic import GHC.Data.FastString diff --git a/compiler/GHC/StgToCmm/Expr.hs b/compiler/GHC/StgToCmm/Expr.hs index 8047571d9f..1b57fc3813 100644 --- a/compiler/GHC/StgToCmm/Expr.hs +++ b/compiler/GHC/StgToCmm/Expr.hs @@ -46,6 +46,7 @@ import GHC.Core.TyCon import GHC.Core.Type ( isUnliftedType ) import GHC.Types.RepType ( isVoidTy, countConRepArgs ) import GHC.Types.CostCentre ( CostCentreStack, currentCCS ) +import GHC.Types.Tickish import GHC.Data.Maybe import GHC.Utils.Misc import GHC.Data.FastString diff --git a/compiler/GHC/Tc/Gen/Bind.hs b/compiler/GHC/Tc/Gen/Bind.hs index 394b4b9c31..27572b2a65 100644 --- a/compiler/GHC/Tc/Gen/Bind.hs +++ b/compiler/GHC/Tc/Gen/Bind.hs @@ -28,7 +28,7 @@ import {-# SOURCE #-} GHC.Tc.Gen.Match ( tcGRHSsPat, tcMatchesFun ) import {-# SOURCE #-} GHC.Tc.Gen.Expr ( tcCheckMonoExpr ) import {-# SOURCE #-} GHC.Tc.TyCl.PatSyn ( tcPatSynDecl, tcPatSynBuilderBind ) -import GHC.Core (CoreTickish, GenTickish (..)) +import GHC.Types.Tickish (CoreTickish, GenTickish (..)) import GHC.Types.CostCentre (mkUserCC, CCFlavour(DeclCC)) import GHC.Driver.Session import GHC.Data.FastString diff --git a/compiler/GHC/Types/Tickish.hs b/compiler/GHC/Types/Tickish.hs new file mode 100644 index 0000000000..b7d28c01d8 --- /dev/null +++ b/compiler/GHC/Types/Tickish.hs @@ -0,0 +1,372 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} + +module GHC.Types.Tickish ( + GenTickish(..), + CoreTickish, StgTickish, CmmTickish, + XTickishId, + tickishCounts, + TickishScoping(..), + tickishScoped, + tickishScopesLike, + tickishFloatable, + tickishCanSplit, + mkNoCount, + mkNoScope, + tickishIsCode, + TickishPlacement(..), + tickishPlace, + tickishContains +) where + +import GHC.Prelude + +import GHC.Core.Type + +import GHC.Unit.Module + +import GHC.Types.CostCentre +import GHC.Types.SrcLoc ( RealSrcSpan, containsSpan ) +import GHC.Types.Var + +import GHC.Utils.Panic + +import Language.Haskell.Syntax.Extension ( NoExtField ) + +import Data.Data + +{- ********************************************************************* +* * + Ticks +* * +************************************************************************ +-} + +-- | Allows attaching extra information to points in expressions + +{- | Used as a data type index for the GenTickish annotations. + See Note [Tickish passes] + -} +data TickishPass + = TickishPassCore + | TickishPassStg + | TickishPassCmm + +{- + Note [Tickish passes] + + Tickish annotations store different information depending on + where they are used. Here's a summary of the differences + between the passes. + + - CoreTickish: Haskell and Core + The tickish annotations store the free variables of + breakpoints. + + - StgTickish: Stg + The GHCi bytecode generator (GHC.StgToByteCode) needs + to know the type of each breakpoint in addition to its + free variables. Since we cannot compute the type from + an STG expression, the tickish annotations store the + type of breakpoints in addition to the free variables. + + - CmmTickish: Cmm + Breakpoints are unsupported and no free variables or + type are stored. + -} + +type family XBreakpoint (pass :: TickishPass) +type instance XBreakpoint 'TickishPassCore = NoExtField +-- | Keep track of the type of breakpoints in STG, for GHCi +type instance XBreakpoint 'TickishPassStg = Type +type instance XBreakpoint 'TickishPassCmm = NoExtField + +type family XTickishId (pass :: TickishPass) +type instance XTickishId 'TickishPassCore = Id +type instance XTickishId 'TickishPassStg = Id +type instance XTickishId 'TickishPassCmm = NoExtField + +type CoreTickish = GenTickish 'TickishPassCore +type StgTickish = GenTickish 'TickishPassStg +-- | Tickish in Cmm context (annotations only) +type CmmTickish = GenTickish 'TickishPassCmm + +-- If you edit this type, you may need to update the GHC formalism +-- See Note [GHC Formalism] in GHC.Core.Lint +data GenTickish pass = + -- | An @{-# SCC #-}@ profiling annotation, either automatically + -- added by the desugarer as a result of -auto-all, or added by + -- the user. + ProfNote { + profNoteCC :: CostCentre, -- ^ the cost centre + profNoteCount :: !Bool, -- ^ bump the entry count? + profNoteScope :: !Bool -- ^ scopes over the enclosed expression + -- (i.e. not just a tick) + } + + -- | A "tick" used by HPC to track the execution of each + -- subexpression in the original source code. + | HpcTick { + tickModule :: Module, + tickId :: !Int + } + + -- | A breakpoint for the GHCi debugger. This behaves like an HPC + -- tick, but has a list of free variables which will be available + -- for inspection in GHCi when the program stops at the breakpoint. + -- + -- NB. we must take account of these Ids when (a) counting free variables, + -- and (b) substituting (don't substitute for them) + | Breakpoint + { breakpointExt :: XBreakpoint pass + , breakpointId :: !Int + , breakpointFVs :: [XTickishId pass] + -- ^ the order of this list is important: + -- it matches the order of the lists in the + -- appropriate entry in 'GHC.ByteCode.Types.ModBreaks'. + -- + -- Careful about substitution! See + -- Note [substTickish] in "GHC.Core.Subst". + } + + -- | A source note. + -- + -- Source notes are pure annotations: Their presence should neither + -- influence compilation nor execution. The semantics are given by + -- causality: The presence of a source note means that a local + -- change in the referenced source code span will possibly provoke + -- the generated code to change. On the flip-side, the functionality + -- of annotated code *must* be invariant against changes to all + -- source code *except* the spans referenced in the source notes + -- (see "Causality of optimized Haskell" paper for details). + -- + -- Therefore extending the scope of any given source note is always + -- valid. Note that it is still undesirable though, as this reduces + -- their usefulness for debugging and profiling. Therefore we will + -- generally try only to make use of this property where it is + -- necessary to enable optimizations. + | SourceNote + { sourceSpan :: RealSrcSpan -- ^ Source covered + , sourceName :: String -- ^ Name for source location + -- (uses same names as CCs) + } + +deriving instance Eq (GenTickish 'TickishPassCore) +deriving instance Ord (GenTickish 'TickishPassCore) +deriving instance Data (GenTickish 'TickishPassCore) + +deriving instance Data (GenTickish 'TickishPassStg) + +deriving instance Eq (GenTickish 'TickishPassCmm) +deriving instance Ord (GenTickish 'TickishPassCmm) +deriving instance Data (GenTickish 'TickishPassCmm) + + +-- | A "counting tick" (where tickishCounts is True) is one that +-- counts evaluations in some way. We cannot discard a counting tick, +-- and the compiler should preserve the number of counting ticks as +-- far as possible. +-- +-- However, we still allow the simplifier to increase or decrease +-- sharing, so in practice the actual number of ticks may vary, except +-- that we never change the value from zero to non-zero or vice versa. +tickishCounts :: GenTickish pass -> Bool +tickishCounts n@ProfNote{} = profNoteCount n +tickishCounts HpcTick{} = True +tickishCounts Breakpoint{} = True +tickishCounts _ = False + + +-- | Specifies the scoping behaviour of ticks. This governs the +-- behaviour of ticks that care about the covered code and the cost +-- associated with it. Important for ticks relating to profiling. +data TickishScoping = + -- | No scoping: The tick does not care about what code it + -- covers. Transformations can freely move code inside as well as + -- outside without any additional annotation obligations + NoScope + + -- | Soft scoping: We want all code that is covered to stay + -- covered. Note that this scope type does not forbid + -- transformations from happening, as long as all results of + -- the transformations are still covered by this tick or a copy of + -- it. For example + -- + -- let x = tick<...> (let y = foo in bar) in baz + -- ===> + -- let x = tick<...> bar; y = tick<...> foo in baz + -- + -- Is a valid transformation as far as "bar" and "foo" is + -- concerned, because both still are scoped over by the tick. + -- + -- Note though that one might object to the "let" not being + -- covered by the tick any more. However, we are generally lax + -- with this - constant costs don't matter too much, and given + -- that the "let" was effectively merged we can view it as having + -- lost its identity anyway. + -- + -- Also note that this scoping behaviour allows floating a tick + -- "upwards" in pretty much any situation. For example: + -- + -- case foo of x -> tick<...> bar + -- ==> + -- tick<...> case foo of x -> bar + -- + -- While this is always legal, we want to make a best effort to + -- only make us of this where it exposes transformation + -- opportunities. + | SoftScope + + -- | Cost centre scoping: We don't want any costs to move to other + -- cost-centre stacks. This means we not only want no code or cost + -- to get moved out of their cost centres, but we also object to + -- code getting associated with new cost-centre ticks - or + -- changing the order in which they get applied. + -- + -- A rule of thumb is that we don't want any code to gain new + -- annotations. However, there are notable exceptions, for + -- example: + -- + -- let f = \y -> foo in tick<...> ... (f x) ... + -- ==> + -- tick<...> ... foo[x/y] ... + -- + -- In-lining lambdas like this is always legal, because inlining a + -- function does not change the cost-centre stack when the + -- function is called. + | CostCentreScope + + deriving (Eq) + +-- | Returns the intended scoping rule for a Tickish +tickishScoped :: GenTickish pass -> TickishScoping +tickishScoped n@ProfNote{} + | profNoteScope n = CostCentreScope + | otherwise = NoScope +tickishScoped HpcTick{} = NoScope +tickishScoped Breakpoint{} = CostCentreScope + -- Breakpoints are scoped: eventually we're going to do call + -- stacks, but also this helps prevent the simplifier from moving + -- breakpoints around and changing their result type (see #1531). +tickishScoped SourceNote{} = SoftScope + +-- | Returns whether the tick scoping rule is at least as permissive +-- as the given scoping rule. +tickishScopesLike :: GenTickish pass -> TickishScoping -> Bool +tickishScopesLike t scope = tickishScoped t `like` scope + where NoScope `like` _ = True + _ `like` NoScope = False + SoftScope `like` _ = True + _ `like` SoftScope = False + CostCentreScope `like` _ = True + +-- | Returns @True@ for ticks that can be floated upwards easily even +-- where it might change execution counts, such as: +-- +-- Just (tick<...> foo) +-- ==> +-- tick<...> (Just foo) +-- +-- This is a combination of @tickishSoftScope@ and +-- @tickishCounts@. Note that in principle splittable ticks can become +-- floatable using @mkNoTick@ -- even though there's currently no +-- tickish for which that is the case. +tickishFloatable :: GenTickish pass -> Bool +tickishFloatable t = t `tickishScopesLike` SoftScope && not (tickishCounts t) + +-- | Returns @True@ for a tick that is both counting /and/ scoping and +-- can be split into its (tick, scope) parts using 'mkNoScope' and +-- 'mkNoTick' respectively. +tickishCanSplit :: GenTickish pass -> Bool +tickishCanSplit ProfNote{profNoteScope = True, profNoteCount = True} + = True +tickishCanSplit _ = False + +mkNoCount :: GenTickish pass -> GenTickish pass +mkNoCount n | not (tickishCounts n) = n + | not (tickishCanSplit n) = panic "mkNoCount: Cannot split!" +mkNoCount n@ProfNote{} = n {profNoteCount = False} +mkNoCount _ = panic "mkNoCount: Undefined split!" + +mkNoScope :: GenTickish pass -> GenTickish pass +mkNoScope n | tickishScoped n == NoScope = n + | not (tickishCanSplit n) = panic "mkNoScope: Cannot split!" +mkNoScope n@ProfNote{} = n {profNoteScope = False} +mkNoScope _ = panic "mkNoScope: Undefined split!" + +-- | Return @True@ if this source annotation compiles to some backend +-- code. Without this flag, the tickish is seen as a simple annotation +-- that does not have any associated evaluation code. +-- +-- What this means that we are allowed to disregard the tick if doing +-- so means that we can skip generating any code in the first place. A +-- typical example is top-level bindings: +-- +-- foo = tick<...> \y -> ... +-- ==> +-- foo = \y -> tick<...> ... +-- +-- Here there is just no operational difference between the first and +-- the second version. Therefore code generation should simply +-- translate the code as if it found the latter. +tickishIsCode :: GenTickish pass -> Bool +tickishIsCode SourceNote{} = False +tickishIsCode _tickish = True -- all the rest for now + + +-- | Governs the kind of expression that the tick gets placed on when +-- annotating for example using @mkTick@. If we find that we want to +-- put a tickish on an expression ruled out here, we try to float it +-- inwards until we find a suitable expression. +data TickishPlacement = + + -- | Place ticks exactly on run-time expressions. We can still + -- move the tick through pure compile-time constructs such as + -- other ticks, casts or type lambdas. This is the most + -- restrictive placement rule for ticks, as all tickishs have in + -- common that they want to track runtime processes. The only + -- legal placement rule for counting ticks. + PlaceRuntime + + -- | As @PlaceRuntime@, but we float the tick through all + -- lambdas. This makes sense where there is little difference + -- between annotating the lambda and annotating the lambda's code. + | PlaceNonLam + + -- | In addition to floating through lambdas, cost-centre style + -- tickishs can also be moved from constructors, non-function + -- variables and literals. For example: + -- + -- let x = scc<...> C (scc<...> y) (scc<...> 3) in ... + -- + -- Neither the constructor application, the variable or the + -- literal are likely to have any cost worth mentioning. And even + -- if y names a thunk, the call would not care about the + -- evaluation context. Therefore removing all annotations in the + -- above example is safe. + | PlaceCostCentre + + deriving (Eq) + +-- | Placement behaviour we want for the ticks +tickishPlace :: GenTickish pass -> TickishPlacement +tickishPlace n@ProfNote{} + | profNoteCount n = PlaceRuntime + | otherwise = PlaceCostCentre +tickishPlace HpcTick{} = PlaceRuntime +tickishPlace Breakpoint{} = PlaceRuntime +tickishPlace SourceNote{} = PlaceNonLam + +-- | Returns whether one tick "contains" the other one, therefore +-- making the second tick redundant. +tickishContains :: Eq (GenTickish pass) + => GenTickish pass -> GenTickish pass -> Bool +tickishContains (SourceNote sp1 n1) (SourceNote sp2 n2) + = containsSpan sp1 sp2 && n1 == n2 + -- compare the String last +tickishContains t1 t2 + = t1 == t2 |