@@ -20,12 +20,9 @@ use dot::IntoCow;
20
20
21
21
use std:: fs;
22
22
use std:: io;
23
- use std:: io:: prelude:: * ;
24
23
use std:: marker:: PhantomData ;
25
24
use std:: path:: Path ;
26
25
27
- use util;
28
-
29
26
use super :: { BitDenotation , DataflowState } ;
30
27
use super :: DataflowBuilder ;
31
28
use super :: DebugFormatted ;
@@ -98,157 +95,161 @@ impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
98
95
}
99
96
100
97
fn node_label ( & self , n : & Node ) -> dot:: LabelText {
101
- // A standard MIR label, as generated by write_node_label, is
102
- // presented in a single column in a table.
103
- //
104
- // The code below does a bunch of formatting work to format a
105
- // node (i.e. MIR basic-block) label with extra
106
- // dataflow-enriched information. In particular, the goal is
107
- // to add extra columns that present the three dataflow
108
- // bitvectors, and the data those bitvectors represent.
109
- //
110
- // It presents it in the following format (where I am
111
- // presenting the table rendering via ASCII art, one line per
112
- // row of the table, and a chunk size of 3 rather than 5):
113
- //
114
- // ------ ----------------------- ------------ --------------------
115
- // [e1, e3, e4]
116
- // [e8, e9] "= ENTRY:" <ENTRY-BITS>
117
- // ------ ----------------------- ------------ --------------------
118
- // Left
119
- // Most
120
- // Column
121
- // Is
122
- // Just
123
- // Normal
124
- // Series
125
- // Of
126
- // MIR
127
- // Stmts
128
- // ------ ----------------------- ------------ --------------------
129
- // [g1, g4, g5] "= GEN:" <GEN-BITS>
130
- // ------ ----------------------- ------------ --------------------
131
- // "KILL:" <KILL-BITS> "=" [k1, k3, k8]
132
- // [k9]
133
- // ------ ----------------------- ------------ --------------------
134
- //
135
- // (In addition, the added dataflow is rendered with a colored
136
- // background just so it will stand out compared to the
137
- // statements.)
98
+ // Node label is something like this:
99
+ // +---------+----------------------------------+------------------+------------------+
100
+ // | ENTRY | MIR | GEN | KILL |
101
+ // +---------+----------------------------------+------------------+------------------+
102
+ // | | 0: StorageLive(_7) | bb3[2]: reserved | bb2[0]: reserved |
103
+ // | | 1: StorageLive(_8) | bb3[2]: active | bb2[0]: active |
104
+ // | | 2: _8 = &mut _1 | | bb4[2]: reserved |
105
+ // | | | | bb4[2]: active |
106
+ // | | | | bb9[0]: reserved |
107
+ // | | | | bb9[0]: active |
108
+ // | | | | bb10[0]: reserved|
109
+ // | | | | bb10[0]: active |
110
+ // | | | | bb11[0]: reserved|
111
+ // | | | | bb11[0]: active |
112
+ // +---------+----------------------------------+------------------+------------------+
113
+ // | [00-00] | _7 = const Foo::twiddle(move _8) | [0c-00] | [f3-0f] |
114
+ // +---------+----------------------------------+------------------+------------------+
138
115
let mut v = Vec :: new ( ) ;
116
+ self . node_label_internal ( n, & mut v, * n, self . mbcx . mir ( ) ) . unwrap ( ) ;
117
+ dot:: LabelText :: html ( String :: from_utf8 ( v) . unwrap ( ) )
118
+ }
119
+
120
+
121
+ fn node_shape ( & self , _n : & Node ) -> Option < dot:: LabelText > {
122
+ Some ( dot:: LabelText :: label ( "none" ) )
123
+ }
124
+
125
+ fn edge_label ( & ' a self , e : & Edge ) -> dot:: LabelText < ' a > {
126
+ let term = self . mbcx . mir ( ) [ e. source ] . terminator ( ) ;
127
+ let label = & term. kind . fmt_successor_labels ( ) [ e. index ] ;
128
+ dot:: LabelText :: label ( label. clone ( ) )
129
+ }
130
+ }
131
+
132
+ impl < ' a , ' tcx , MWF , P > Graph < ' a , ' tcx , MWF , P >
133
+ where MWF : MirWithFlowState < ' tcx > ,
134
+ P : Fn ( & MWF :: BD , <MWF :: BD as BitDenotation >:: Idx ) -> DebugFormatted ,
135
+ {
136
+ /// Generate the node label
137
+ fn node_label_internal < W : io:: Write > ( & self ,
138
+ n : & Node ,
139
+ w : & mut W ,
140
+ block : BasicBlock ,
141
+ mir : & Mir ) -> io:: Result < ( ) > {
142
+ // Header rows
143
+ const HDRS : [ & ' static str ; 4 ] = [ "ENTRY" , "MIR" , "GEN" , "KILL" ] ;
144
+ const HDR_FMT : & ' static str = "bgcolor=\" grey\" " ;
145
+ write ! ( w, "<table><tr><td rowspan=\" {}\" >" , HDRS . len( ) ) ?;
146
+ write ! ( w, "{:?}" , block. index( ) ) ?;
147
+ write ! ( w, "</td></tr><tr>" ) ?;
148
+ for hdr in & HDRS {
149
+ write ! ( w, "<td {}>{}</td>" , HDR_FMT , hdr) ?;
150
+ }
151
+ write ! ( w, "</tr>" ) ?;
152
+
153
+ // Data row
154
+ self . node_label_verbose_row ( n, w, block, mir) ?;
155
+ self . node_label_final_row ( n, w, block, mir) ?;
156
+ write ! ( w, "</table>" ) ?;
157
+
158
+ Ok ( ( ) )
159
+ }
160
+
161
+ /// Build the verbose row: full MIR data, and detailed gen/kill/entry sets
162
+ fn node_label_verbose_row < W : io:: Write > ( & self ,
163
+ n : & Node ,
164
+ w : & mut W ,
165
+ block : BasicBlock ,
166
+ mir : & Mir )
167
+ -> io:: Result < ( ) > {
139
168
let i = n. index ( ) ;
140
- let chunk_size = 5 ;
141
- const BG_FLOWCONTENT : & ' static str = r#"bgcolor="pink""# ;
142
- const ALIGN_RIGHT : & ' static str = r#"align="right""# ;
143
- const FACE_MONOSPACE : & ' static str = r#"FACE="Courier""# ;
144
- fn chunked_present_left < W : io:: Write > ( w : & mut W ,
145
- interpreted : & [ DebugFormatted ] ,
146
- chunk_size : usize )
147
- -> io:: Result < ( ) >
148
- {
149
- // This function may emit a sequence of <tr>'s, but it
150
- // always finishes with an (unfinished)
151
- // <tr><td></td><td>
152
- //
153
- // Thus, after being called, one should finish both the
154
- // pending <td> as well as the <tr> itself.
155
- let mut seen_one = false ;
156
- for c in interpreted. chunks ( chunk_size) {
157
- if seen_one {
158
- // if not the first row, finish off the previous row
159
- write ! ( w, "</td><td></td><td></td></tr>" ) ?;
169
+
170
+ macro_rules! dump_set_for {
171
+ ( $set: ident) => {
172
+ write!( w, "<td>" ) ?;
173
+
174
+ let flow = self . mbcx. flow_state( ) ;
175
+ let entry_interp = flow. interpret_set( & flow. operator,
176
+ flow. sets. $set( i) ,
177
+ & self . render_idx) ;
178
+ for e in & entry_interp {
179
+ write!( w, "{:?}<br/>" , e) ?;
160
180
}
161
- write ! ( w, "<tr><td></td><td {bg} {align}>{objs:?}" ,
162
- bg = BG_FLOWCONTENT ,
163
- align = ALIGN_RIGHT ,
164
- objs = c) ?;
165
- seen_one = true ;
181
+ write!( w, "</td>" ) ?;
166
182
}
167
- if !seen_one {
168
- write ! ( w, "<tr><td></td><td {bg} {align}>[]" ,
169
- bg = BG_FLOWCONTENT ,
170
- align = ALIGN_RIGHT ) ?;
183
+ }
184
+
185
+ write ! ( w, "<tr>" ) ?;
186
+ // Entry
187
+ dump_set_for ! ( on_entry_set_for) ;
188
+
189
+ // MIR statements
190
+ write ! ( w, "<td>" ) ?;
191
+ {
192
+ let data = & mir[ block] ;
193
+ for ( i, statement) in data. statements . iter ( ) . enumerate ( ) {
194
+ write ! ( w, "{}<br align=\" left\" />" ,
195
+ dot:: escape_html( & format!( "{:3}: {:?}" , i, statement) ) ) ?;
171
196
}
172
- Ok ( ( ) )
173
197
}
174
- util:: write_graphviz_node_label (
175
- * n, self . mbcx . mir ( ) , & mut v, 4 ,
176
- |w| {
177
- let flow = self . mbcx . flow_state ( ) ;
178
- let entry_interp = flow. interpret_set ( & flow. operator ,
179
- flow. sets . on_entry_set_for ( i) ,
180
- & self . render_idx ) ;
181
- chunked_present_left ( w, & entry_interp[ ..] , chunk_size) ?;
182
- let bits_per_block = flow. sets . bits_per_block ( ) ;
183
- let entry = flow. sets . on_entry_set_for ( i) ;
184
- debug ! ( "entry set for i={i} bits_per_block: {bpb} entry: {e:?} interp: {ei:?}" ,
185
- i=i, e=entry, bpb=bits_per_block, ei=entry_interp) ;
186
- write ! ( w, "= ENTRY:</td><td {bg}><FONT {face}>{entrybits:?}</FONT></td>\
187
- <td></td></tr>",
188
- bg = BG_FLOWCONTENT ,
189
- face = FACE_MONOSPACE ,
190
- entrybits=bits_to_string( entry. words( ) , bits_per_block) )
191
- } ,
192
- |w| {
198
+ write ! ( w, "</td>" ) ?;
199
+
200
+ // Gen
201
+ dump_set_for ! ( gen_set_for) ;
202
+
203
+ // Kill
204
+ dump_set_for ! ( kill_set_for) ;
205
+
206
+ write ! ( w, "</tr>" ) ?;
207
+
208
+ Ok ( ( ) )
209
+ }
210
+
211
+ /// Build the summary row: terminator, gen/kill/entry bit sets
212
+ fn node_label_final_row < W : io:: Write > ( & self ,
213
+ n : & Node ,
214
+ w : & mut W ,
215
+ block : BasicBlock ,
216
+ mir : & Mir )
217
+ -> io:: Result < ( ) > {
218
+ let i = n. index ( ) ;
219
+
220
+ macro_rules! dump_set_for {
221
+ ( $set: ident) => {
193
222
let flow = self . mbcx. flow_state( ) ;
194
- let gen_interp =
195
- flow. interpret_set ( & flow. operator , flow. sets . gen_set_for ( i) , & self . render_idx ) ;
196
- let kill_interp =
197
- flow. interpret_set ( & flow. operator , flow. sets . kill_set_for ( i) , & self . render_idx ) ;
198
- chunked_present_left ( w, & gen_interp[ ..] , chunk_size) ?;
199
223
let bits_per_block = flow. sets. bits_per_block( ) ;
200
- {
201
- let gen = flow. sets . gen_set_for ( i) ;
202
- debug ! ( "gen set for i={i} bits_per_block: {bpb} gen: {g:?} interp: {gi:?}" ,
203
- i=i, g=gen , bpb=bits_per_block, gi=gen_interp) ;
204
- write ! ( w, " = GEN:</td><td {bg}><FONT {face}>{genbits:?}</FONT></td>\
205
- <td></td></tr>",
206
- bg = BG_FLOWCONTENT ,
207
- face = FACE_MONOSPACE ,
208
- genbits=bits_to_string( gen . words( ) , bits_per_block) ) ?;
209
- }
224
+ let set = flow. sets. $set( i) ;
225
+ write!( w, "<td>{:?}</td>" ,
226
+ dot:: escape_html( & bits_to_string( set. words( ) , bits_per_block) ) ) ?;
227
+ }
228
+ }
210
229
211
- {
212
- let kill = flow. sets . kill_set_for ( i) ;
213
- debug ! ( "kill set for i={i} bits_per_block: {bpb} kill: {k:?} interp: {ki:?}" ,
214
- i=i, k=kill, bpb=bits_per_block, ki=kill_interp) ;
215
- write ! ( w, "<tr><td></td><td {bg} {align}>KILL:</td>\
216
- <td {bg}><FONT {face}>{killbits:?}</FONT></td>",
217
- bg = BG_FLOWCONTENT ,
218
- align = ALIGN_RIGHT ,
219
- face = FACE_MONOSPACE ,
220
- killbits=bits_to_string( kill. words( ) , bits_per_block) ) ?;
221
- }
230
+ write ! ( w, "<tr>" ) ?;
231
+ // Entry
232
+ dump_set_for ! ( on_entry_set_for) ;
222
233
223
- // (chunked_present_right)
224
- let mut seen_one = false ;
225
- for k in kill_interp. chunks ( chunk_size) {
226
- if !seen_one {
227
- // continuation of row; this is fourth <td>
228
- write ! ( w, "<td {bg}>= {kill:?}</td></tr>" ,
229
- bg = BG_FLOWCONTENT ,
230
- kill=k) ?;
231
- } else {
232
- // new row, with indent of three <td>'s
233
- write ! ( w, "<tr><td></td><td></td><td></td><td {bg}>{kill:?}</td></tr>" ,
234
- bg = BG_FLOWCONTENT ,
235
- kill=k) ?;
236
- }
237
- seen_one = true ;
238
- }
239
- if !seen_one {
240
- write ! ( w, "<td {bg}>= []</td></tr>" ,
241
- bg = BG_FLOWCONTENT ) ?;
242
- }
234
+ // Terminator
235
+ write ! ( w, "<td>" ) ?;
236
+ {
237
+ let data = & mir[ block] ;
238
+ let mut terminator_head = String :: new ( ) ;
239
+ data. terminator ( ) . kind . fmt_head ( & mut terminator_head) . unwrap ( ) ;
240
+ write ! ( w, "{}" , dot:: escape_html( & terminator_head) ) ?;
241
+ }
242
+ write ! ( w, "</td>" ) ?;
243
243
244
- Ok ( ( ) )
245
- } )
246
- . unwrap ( ) ;
247
- dot:: LabelText :: html ( String :: from_utf8 ( v) . unwrap ( ) )
248
- }
244
+ // Gen
245
+ dump_set_for ! ( gen_set_for) ;
249
246
250
- fn node_shape ( & self , _n : & Node ) -> Option < dot:: LabelText > {
251
- Some ( dot:: LabelText :: label ( "none" ) )
247
+ // Kill
248
+ dump_set_for ! ( kill_set_for) ;
249
+
250
+ write ! ( w, "</tr>" ) ?;
251
+
252
+ Ok ( ( ) )
252
253
}
253
254
}
254
255
0 commit comments