| ... |
... |
@@ -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,21 @@ 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 this, their order would
|
|
|
107
|
+ fall back to the Unique-driven input order -- exactly the churn we set out
|
|
|
108
|
+ to remove. (In tidied dumps like -ddump-simpl the floats already have
|
|
|
109
|
+ distinct names lvl, lvl1, ...; this tie-break additionally stabilises the
|
|
|
110
|
+ untidied dumps -ddump-simpl-iterations, -dverbose-core2core etc.) It is a
|
|
|
111
|
+ best-effort tie-break, not a total order: two RHSs that agree on the
|
|
|
112
|
+ floated literal and on every size statistic still fall back to input
|
|
|
113
|
+ order. And it is Unique-independent for the floats we target -- the one
|
|
|
114
|
+ exception is a rubbish literal (LitRubbish), whose 'cmpLit' compares the
|
|
|
115
|
+ underlying type with the Unique-dependent 'nonDetCmpType'; that does not
|
|
|
116
|
+ arise for the numeric CAFs this targets.
|
|
103
|
117
|
|
|
104
|
118
|
Recursive groups are never split: a 'Rec' is one 'CoreBind', placed as a unit by
|
|
105
|
119
|
its earliest-source member, with its members sorted by the same key.
|
| ... |
... |
@@ -114,24 +128,36 @@ suffer the cross-module churn this flag addresses. |
|
114
|
128
|
useful for debugging the compiler itself.
|
|
115
|
129
|
-}
|
|
116
|
130
|
|
|
|
131
|
+-- | The sort key for one top-level binder. The trailing 'RhsKey' is a
|
|
|
132
|
+-- content-based tiebreak, used only when two binders agree on everything
|
|
|
133
|
+-- before it. See Note [Stable Core dump order].
|
|
|
134
|
+type DumpSortKey =
|
|
|
135
|
+ ( Int -- source-span bucket: 0 = real span, 1 = noSrcSpan (sorts last)
|
|
|
136
|
+ , Int -- source-span start line
|
|
|
137
|
+ , Int -- source-span start column
|
|
|
138
|
+ , Int -- $-rank: 0 = derived ($w/$s) binder, 1 = its origin
|
|
|
139
|
+ , String -- the OccName string, a lexical tiebreak
|
|
|
140
|
+ , RhsKey -- content-based tiebreak (see 'rhsKey')
|
|
|
141
|
+ )
|
|
|
142
|
+
|
|
117
|
143
|
-- | Reorder a 'CoreProgram' into a stable, source-location-driven order for
|
|
118
|
144
|
-- dumping. See Note [Stable Core dump order]. Used by 'dumpPassResult' when
|
|
119
|
145
|
-- -dstable-core-dump-order is enabled.
|
|
120
|
146
|
sortCoreBindingsForDump :: CoreProgram -> CoreProgram
|
|
121
|
147
|
sortCoreBindingsForDump = sortOn bindKey . map sortRecMembers
|
|
122
|
148
|
where
|
|
123
|
|
- sortRecMembers (Rec prs) = Rec (sortOn (bndrKey . fst) prs)
|
|
|
149
|
+ sortRecMembers (Rec prs) = Rec (sortOn (uncurry elemKey) prs)
|
|
124
|
150
|
sortRecMembers b = b
|
|
125
|
151
|
|
|
126
|
|
- -- 'sortRecMembers' runs first, so a 'Rec' is already sorted by 'bndrKey'
|
|
|
152
|
+ -- 'sortRecMembers' runs first, so a 'Rec' is already sorted by 'elemKey'
|
|
127
|
153
|
-- 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"
|
|
|
154
|
+ bindKey :: CoreBind -> DumpSortKey
|
|
|
155
|
+ bindKey (NonRec b rhs) = elemKey b rhs
|
|
|
156
|
+ bindKey (Rec ((b,rhs):_)) = elemKey b rhs
|
|
|
157
|
+ bindKey (Rec []) = panic "sortCoreBindingsForDump: empty Rec"
|
|
132
|
158
|
|
|
133
|
|
- bndrKey :: CoreBndr -> (Int, Int, Int, Int, String)
|
|
134
|
|
- bndrKey b = (bucket, line, col, dollar_rank, s)
|
|
|
159
|
+ elemKey :: CoreBndr -> CoreExpr -> DumpSortKey
|
|
|
160
|
+ elemKey b rhs = (bucket, line, col, dollar_rank, s, rhsKey rhs)
|
|
135
|
161
|
where
|
|
136
|
162
|
s = getOccString b
|
|
137
|
163
|
(bucket, line, col) = case getSrcSpan b of
|
| ... |
... |
@@ -145,6 +171,27 @@ sortCoreBindingsForDump = sortOn bindKey . map sortRecMembers |
|
145
|
171
|
dollar_rank | '$' `elem` s = 0
|
|
146
|
172
|
| otherwise = 1
|
|
147
|
173
|
|
|
|
174
|
+-- | A cheap tie-break on a binder's right-hand side, used to order binders that
|
|
|
175
|
+-- are otherwise indistinguishable -- in practice the anonymous floats, which all
|
|
|
176
|
+-- share OccName \"lvl\" and 'noSrcSpan' (see 'GHC.Core.Opt.SetLevels.newLvlVar').
|
|
|
177
|
+-- It pairs the floated literal (if any, looking through the @I#@-style box and
|
|
|
178
|
+-- casts/ticks) with the RHS size statistics. For its Unique-independence and
|
|
|
179
|
+-- best-effort caveats see Note [Stable Core dump order].
|
|
|
180
|
+type RhsKey =
|
|
|
181
|
+ ( Maybe Literal -- the floated literal, if any (Nothing sorts first)
|
|
|
182
|
+ , (Int, Int, Int, Int, Int) -- exprStats counts: terms, types, coercions, value binds, join binds
|
|
|
183
|
+ )
|
|
|
184
|
+
|
|
|
185
|
+rhsKey :: CoreExpr -> RhsKey
|
|
|
186
|
+rhsKey rhs = (litOf rhs, statsTuple (exprStats rhs))
|
|
|
187
|
+ where
|
|
|
188
|
+ statsTuple (CS tm ty co vb jb) = (tm, ty, co, vb, jb)
|
|
|
189
|
+ litOf (Lit l) = Just l
|
|
|
190
|
+ litOf (App f a) = case a of { Lit l -> Just l; _ -> litOf f }
|
|
|
191
|
+ litOf (Cast e _) = litOf e
|
|
|
192
|
+ litOf (Tick _ e) = litOf e
|
|
|
193
|
+ litOf _ = Nothing
|
|
|
194
|
+
|
|
148
|
195
|
instance OutputableBndr b => Outputable (Bind b) where
|
|
149
|
196
|
ppr bind = ppr_bind noAnn bind
|
|
150
|
197
|
|