@@ -20,12 +20,9 @@ use dot::IntoCow;
2020
2121use std:: fs;
2222use std:: io;
23- use std:: io:: prelude:: * ;
2423use std:: marker:: PhantomData ;
2524use std:: path:: Path ;
2625
27- use util;
28-
2926use super :: { BitDenotation , DataflowState } ;
3027use super :: DataflowBuilder ;
3128use super :: DebugFormatted ;
@@ -98,157 +95,161 @@ impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
9895 }
9996
10097 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+ // +---------+----------------------------------+------------------+------------------+
138115 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 < ( ) > {
139168 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) ?;
160180 }
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>" ) ?;
166182 }
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) ) ) ?;
171196 }
172- Ok ( ( ) )
173197 }
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) => {
193222 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) ?;
199223 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+ }
210229
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) ;
222233
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>" ) ?;
243243
244- Ok ( ( ) )
245- } )
246- . unwrap ( ) ;
247- dot:: LabelText :: html ( String :: from_utf8 ( v) . unwrap ( ) )
248- }
244+ // Gen
245+ dump_set_for ! ( gen_set_for) ;
249246
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 ( ( ) )
252253 }
253254}
254255
0 commit comments