| ... |
... |
@@ -28,10 +28,10 @@ module GHC.Core.Ppr ( |
|
28
|
28
|
import GHC.Prelude
|
|
29
|
29
|
|
|
30
|
30
|
import GHC.Core
|
|
31
|
|
-import GHC.Core.Stats (exprStats)
|
|
|
31
|
+import GHC.Core.Stats (CoreStats(..), exprStats)
|
|
32
|
32
|
import GHC.Types.Fixity (LexicalFixity(..))
|
|
33
|
|
-import GHC.Types.Literal( pprLiteral )
|
|
34
|
|
-import GHC.Types.Name( pprInfixName, pprPrefixName, getOccString, getSrcSpan )
|
|
|
33
|
+import GHC.Types.Literal( Literal, pprLiteral )
|
|
|
34
|
+import GHC.Types.Name( getOccString, getSrcSpan, pprInfixName, pprPrefixName )
|
|
35
|
35
|
import GHC.Types.Var
|
|
36
|
36
|
import GHC.Types.Id
|
|
37
|
37
|
import GHC.Types.Id.Info
|
| ... |
... |
@@ -46,8 +46,8 @@ import GHC.Types.Basic |
|
46
|
46
|
import GHC.Utils.Misc
|
|
47
|
47
|
import GHC.Utils.Outputable
|
|
48
|
48
|
import GHC.Utils.Panic (panic)
|
|
49
|
|
-import GHC.Types.SrcLoc ( SrcSpan(..), srcSpanStartLine, srcSpanStartCol
|
|
50
|
|
- , pprUserRealSpan )
|
|
|
49
|
+import GHC.Types.SrcLoc ( SrcSpan(..), pprUserRealSpan, srcSpanStartCol
|
|
|
50
|
+ , srcSpanStartLine )
|
|
51
|
51
|
import GHC.Types.Tickish
|
|
52
|
52
|
|
|
53
|
53
|
import Data.List ( sortOn )
|
| ... |
... |
@@ -99,7 +99,18 @@ Uniques*, so two dumps line up across rebuilds. The sort key is: |
|
99
|
99
|
whether the OccName *contains* a '$', which marks a derived binder: a worker
|
|
100
|
100
|
is @$wfoo@, but a call-site specialisation is tidied to @bar_$sfoo@ (no
|
|
101
|
101
|
leading '$'), so a leading-'$' test would miss it.
|
|
102
|
|
- 3. the OccName string, as a final lexical, deterministic tie-break.
|
|
|
102
|
+ 3. the OccName string, as a lexical, deterministic tie-break.
|
|
|
103
|
+ 4. a content-based tie-break on the right-hand side ('rhsKey'): the floated
|
|
|
104
|
+ literal, if any, then the RHS size statistics. This matters for the
|
|
|
105
|
+ anonymous floats: 'newLvlVar' builds them all with OccName "lvl" and
|
|
|
106
|
+ noSrcSpan, so keys 1-3 are identical and without it their order would fall
|
|
|
107
|
+ back to the Unique-driven input order -- the churn we set out to remove.
|
|
|
108
|
+ (Tidied dumps like -ddump-simpl give the floats distinct names lvl,
|
|
|
109
|
+ lvl1, ...; this additionally stabilises untidied dumps such as
|
|
|
110
|
+ -ddump-simpl-iterations.) It is only a best-effort tie-break -- RHSs
|
|
|
111
|
+ agreeing on both components keep their input order -- and Unique-independent
|
|
|
112
|
+ for the numeric CAFs we target (a rubbish literal is the exception: its
|
|
|
113
|
+ 'cmpLit' falls back to the Unique-dependent 'nonDetCmpType').
|
|
103
|
114
|
|
|
104
|
115
|
Recursive groups are never split: a 'Rec' is one 'CoreBind', placed as a unit by
|
|
105
|
116
|
its earliest-source member, with its members sorted by the same key.
|
| ... |
... |
@@ -114,24 +125,36 @@ suffer the cross-module churn this flag addresses. |
|
114
|
125
|
useful for debugging the compiler itself.
|
|
115
|
126
|
-}
|
|
116
|
127
|
|
|
|
128
|
+-- | The sort key for one top-level binder. The trailing 'RhsKey' is a
|
|
|
129
|
+-- content-based tiebreak, used only when two binders agree on everything
|
|
|
130
|
+-- before it. See Note [Stable Core dump order].
|
|
|
131
|
+type DumpSortKey =
|
|
|
132
|
+ ( Int -- source-span bucket: 0 = real span, 1 = noSrcSpan (sorts last)
|
|
|
133
|
+ , Int -- source-span start line
|
|
|
134
|
+ , Int -- source-span start column
|
|
|
135
|
+ , Int -- dollar-rank: 0 = derived ($w/$s) binder, 1 = its origin
|
|
|
136
|
+ , String -- the OccName string, a lexical tiebreak
|
|
|
137
|
+ , RhsKey -- content-based tiebreak (see 'rhsKey')
|
|
|
138
|
+ )
|
|
|
139
|
+
|
|
117
|
140
|
-- | Reorder a 'CoreProgram' into a stable, source-location-driven order for
|
|
118
|
141
|
-- dumping. See Note [Stable Core dump order]. Used by 'dumpPassResult' when
|
|
119
|
142
|
-- -dstable-core-dump-order is enabled.
|
|
120
|
143
|
sortCoreBindingsForDump :: CoreProgram -> CoreProgram
|
|
121
|
144
|
sortCoreBindingsForDump = sortOn bindKey . map sortRecMembers
|
|
122
|
145
|
where
|
|
123
|
|
- sortRecMembers (Rec prs) = Rec (sortOn (bndrKey . fst) prs)
|
|
|
146
|
+ sortRecMembers (Rec prs) = Rec (sortOn (uncurry elemKey) prs)
|
|
124
|
147
|
sortRecMembers b = b
|
|
125
|
148
|
|
|
126
|
|
- -- 'sortRecMembers' runs first, so a 'Rec' is already sorted by 'bndrKey'
|
|
|
149
|
+ -- 'sortRecMembers' runs first, so a 'Rec' is already sorted by 'elemKey'
|
|
127
|
150
|
-- when 'bindKey' sees it; its first member is therefore the minimum key.
|
|
128
|
|
- bindKey :: CoreBind -> (Int, Int, Int, Int, String)
|
|
129
|
|
- bindKey (NonRec b _) = bndrKey b
|
|
130
|
|
- bindKey (Rec ((b,_):_)) = bndrKey b
|
|
131
|
|
- bindKey (Rec []) = panic "sortCoreBindingsForDump: empty Rec"
|
|
|
151
|
+ bindKey :: CoreBind -> DumpSortKey
|
|
|
152
|
+ bindKey (NonRec b rhs) = elemKey b rhs
|
|
|
153
|
+ bindKey (Rec ((b,rhs):_)) = elemKey b rhs
|
|
|
154
|
+ bindKey (Rec []) = panic "sortCoreBindingsForDump: empty Rec"
|
|
132
|
155
|
|
|
133
|
|
- bndrKey :: CoreBndr -> (Int, Int, Int, Int, String)
|
|
134
|
|
- bndrKey b = (bucket, line, col, dollar_rank, s)
|
|
|
156
|
+ elemKey :: CoreBndr -> CoreExpr -> DumpSortKey
|
|
|
157
|
+ elemKey b rhs = (bucket, line, col, dollar_rank, s, rhsKey rhs)
|
|
135
|
158
|
where
|
|
136
|
159
|
s = getOccString b
|
|
137
|
160
|
(bucket, line, col) = case getSrcSpan b of
|
| ... |
... |
@@ -145,6 +168,23 @@ sortCoreBindingsForDump = sortOn bindKey . map sortRecMembers |
|
145
|
168
|
dollar_rank | '$' `elem` s = 0
|
|
146
|
169
|
| otherwise = 1
|
|
147
|
170
|
|
|
|
171
|
+-- | A content-based tie-break on a binder's right-hand side: see point 4 of
|
|
|
172
|
+-- Note [Stable Core dump order].
|
|
|
173
|
+type RhsKey =
|
|
|
174
|
+ ( Maybe Literal -- the floated literal, if any (Nothing sorts first)
|
|
|
175
|
+ , (Int, Int, Int, Int, Int) -- exprStats counts: terms, types, coercions, value binds, join binds
|
|
|
176
|
+ )
|
|
|
177
|
+
|
|
|
178
|
+rhsKey :: CoreExpr -> RhsKey
|
|
|
179
|
+rhsKey rhs = (litOf rhs, statsTuple (exprStats rhs))
|
|
|
180
|
+ where
|
|
|
181
|
+ statsTuple (CS tm ty co vb jb) = (tm, ty, co, vb, jb)
|
|
|
182
|
+ litOf (Lit l) = Just l
|
|
|
183
|
+ litOf (App f a) = case a of { Lit l -> Just l; _ -> litOf f }
|
|
|
184
|
+ litOf (Cast e _) = litOf e
|
|
|
185
|
+ litOf (Tick _ e) = litOf e
|
|
|
186
|
+ litOf _ = Nothing
|
|
|
187
|
+
|
|
148
|
188
|
instance OutputableBndr b => Outputable (Bind b) where
|
|
149
|
189
|
ppr bind = ppr_bind noAnn bind
|
|
150
|
190
|
|