]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/dataflow.rs
Port a bunch of code new-visitor; all of these ports were
[rust.git] / src / librustc / middle / dataflow.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11
12 //! A module for propagating forward dataflow information. The analysis
13 //! assumes that the items to be propagated can be represented as bits
14 //! and thus uses bitvectors. Your job is simply to specify the so-called
15 //! GEN and KILL bits for each expression.
16
17 pub use self::EntryOrExit::*;
18
19 use middle::cfg;
20 use middle::cfg::CFGIndex;
21 use middle::ty;
22 use std::io;
23 use std::usize;
24 use syntax::ast;
25 use syntax::ast_util::IdRange;
26 use syntax::print::pp;
27 use syntax::print::pprust::PrintState;
28 use util::nodemap::NodeMap;
29 use rustc_front::hir;
30 use rustc_front::intravisit;
31 use rustc_front::print::pprust;
32
33
34 #[derive(Copy, Clone, Debug)]
35 pub enum EntryOrExit {
36     Entry,
37     Exit,
38 }
39
40 #[derive(Clone)]
41 pub struct DataFlowContext<'a, 'tcx: 'a, O> {
42     tcx: &'a ty::ctxt<'tcx>,
43
44     /// a name for the analysis using this dataflow instance
45     analysis_name: &'static str,
46
47     /// the data flow operator
48     oper: O,
49
50     /// number of bits to propagate per id
51     bits_per_id: usize,
52
53     /// number of words we will use to store bits_per_id.
54     /// equal to bits_per_id/usize::BITS rounded up.
55     words_per_id: usize,
56
57     // mapping from node to cfg node index
58     // FIXME (#6298): Shouldn't this go with CFG?
59     nodeid_to_index: NodeMap<Vec<CFGIndex>>,
60
61     // Bit sets per cfg node.  The following three fields (`gens`, `kills`,
62     // and `on_entry`) all have the same structure. For each id in
63     // `id_range`, there is a range of words equal to `words_per_id`.
64     // So, to access the bits for any given id, you take a slice of
65     // the full vector (see the method `compute_id_range()`).
66
67     /// bits generated as we exit the cfg node. Updated by `add_gen()`.
68     gens: Vec<usize>,
69
70     /// bits killed as we exit the cfg node, or non-locally jump over
71     /// it. Updated by `add_kill(KillFrom::ScopeEnd)`.
72     scope_kills: Vec<usize>,
73
74     /// bits killed as we exit the cfg node directly; if it is jumped
75     /// over, e.g. via `break`, the kills are not reflected in the
76     /// jump's effects. Updated by `add_kill(KillFrom::Execution)`.
77     action_kills: Vec<usize>,
78
79     /// bits that are valid on entry to the cfg node. Updated by
80     /// `propagate()`.
81     on_entry: Vec<usize>,
82 }
83
84 pub trait BitwiseOperator {
85     /// Joins two predecessor bits together, typically either `|` or `&`
86     fn join(&self, succ: usize, pred: usize) -> usize;
87 }
88
89 /// Parameterization for the precise form of data flow that is used.
90 pub trait DataFlowOperator : BitwiseOperator {
91     /// Specifies the initial value for each bit in the `on_entry` set
92     fn initial_value(&self) -> bool;
93 }
94
95 struct PropagationContext<'a, 'b: 'a, 'tcx: 'b, O: 'a> {
96     dfcx: &'a mut DataFlowContext<'b, 'tcx, O>,
97     changed: bool
98 }
99
100 fn get_cfg_indices<'a>(id: ast::NodeId, index: &'a NodeMap<Vec<CFGIndex>>) -> &'a [CFGIndex] {
101     let opt_indices = index.get(&id);
102     opt_indices.map(|v| &v[..]).unwrap_or(&[])
103 }
104
105 impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
106     fn has_bitset_for_nodeid(&self, n: ast::NodeId) -> bool {
107         assert!(n != ast::DUMMY_NODE_ID);
108         self.nodeid_to_index.contains_key(&n)
109     }
110 }
111
112 impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O> {
113     fn pre(&self,
114            ps: &mut pprust::State,
115            node: pprust::AnnNode) -> io::Result<()> {
116         let id = match node {
117             pprust::NodeName(_) => 0,
118             pprust::NodeExpr(expr) => expr.id,
119             pprust::NodeBlock(blk) => blk.id,
120             pprust::NodeItem(_) | pprust::NodeSubItem(_) => 0,
121             pprust::NodePat(pat) => pat.id
122         };
123
124         if !self.has_bitset_for_nodeid(id) {
125             return Ok(());
126         }
127
128         assert!(self.bits_per_id > 0);
129         let indices = get_cfg_indices(id, &self.nodeid_to_index);
130         for &cfgidx in indices {
131             let (start, end) = self.compute_id_range(cfgidx);
132             let on_entry = &self.on_entry[start.. end];
133             let entry_str = bits_to_string(on_entry);
134
135             let gens = &self.gens[start.. end];
136             let gens_str = if gens.iter().any(|&u| u != 0) {
137                 format!(" gen: {}", bits_to_string(gens))
138             } else {
139                 "".to_string()
140             };
141
142             let action_kills = &self.action_kills[start .. end];
143             let action_kills_str = if action_kills.iter().any(|&u| u != 0) {
144                 format!(" action_kill: {}", bits_to_string(action_kills))
145             } else {
146                 "".to_string()
147             };
148
149             let scope_kills = &self.scope_kills[start .. end];
150             let scope_kills_str = if scope_kills.iter().any(|&u| u != 0) {
151                 format!(" scope_kill: {}", bits_to_string(scope_kills))
152             } else {
153                 "".to_string()
154             };
155
156             try!(ps.synth_comment(
157                 format!("id {}: {}{}{}{}", id, entry_str,
158                         gens_str, action_kills_str, scope_kills_str)));
159             try!(pp::space(&mut ps.s));
160         }
161         Ok(())
162     }
163 }
164
165 fn build_nodeid_to_index(decl: Option<&hir::FnDecl>,
166                          cfg: &cfg::CFG) -> NodeMap<Vec<CFGIndex>> {
167     let mut index = NodeMap();
168
169     // FIXME (#6298): Would it be better to fold formals from decl
170     // into cfg itself?  i.e. introduce a fn-based flow-graph in
171     // addition to the current block-based flow-graph, rather than
172     // have to put traversals like this here?
173     match decl {
174         None => {}
175         Some(decl) => add_entries_from_fn_decl(&mut index, decl, cfg.entry)
176     }
177
178     cfg.graph.each_node(|node_idx, node| {
179         if let cfg::CFGNodeData::AST(id) = node.data {
180             index.entry(id).or_insert(vec![]).push(node_idx);
181         }
182         true
183     });
184
185     return index;
186
187     fn add_entries_from_fn_decl(index: &mut NodeMap<Vec<CFGIndex>>,
188                                 decl: &hir::FnDecl,
189                                 entry: CFGIndex) {
190         //! add mappings from the ast nodes for the formal bindings to
191         //! the entry-node in the graph.
192         struct Formals<'a> {
193             entry: CFGIndex,
194             index: &'a mut NodeMap<Vec<CFGIndex>>,
195         }
196         let mut formals = Formals { entry: entry, index: index };
197         intravisit::walk_fn_decl(&mut formals, decl);
198         impl<'a, 'v> intravisit::Visitor<'v> for Formals<'a> {
199             fn visit_pat(&mut self, p: &hir::Pat) {
200                 self.index.entry(p.id).or_insert(vec![]).push(self.entry);
201                 intravisit::walk_pat(self, p)
202             }
203         }
204     }
205 }
206
207 /// Flag used by `add_kill` to indicate whether the provided kill
208 /// takes effect only when control flows directly through the node in
209 /// question, or if the kill's effect is associated with any
210 /// control-flow directly through or indirectly over the node.
211 #[derive(Copy, Clone, PartialEq, Debug)]
212 pub enum KillFrom {
213     /// A `ScopeEnd` kill is one that takes effect when any control
214     /// flow goes over the node. A kill associated with the end of the
215     /// scope of a variable declaration `let x;` is an example of a
216     /// `ScopeEnd` kill.
217     ScopeEnd,
218
219     /// An `Execution` kill is one that takes effect only when control
220     /// flow goes through the node to completion. A kill associated
221     /// with an assignment statement `x = expr;` is an example of an
222     /// `Execution` kill.
223     Execution,
224 }
225
226 impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
227     pub fn new(tcx: &'a ty::ctxt<'tcx>,
228                analysis_name: &'static str,
229                decl: Option<&hir::FnDecl>,
230                cfg: &cfg::CFG,
231                oper: O,
232                id_range: IdRange,
233                bits_per_id: usize) -> DataFlowContext<'a, 'tcx, O> {
234         let words_per_id = (bits_per_id + usize::BITS - 1) / usize::BITS;
235         let num_nodes = cfg.graph.all_nodes().len();
236
237         debug!("DataFlowContext::new(analysis_name: {}, id_range={:?}, \
238                                      bits_per_id={}, words_per_id={}) \
239                                      num_nodes: {}",
240                analysis_name, id_range, bits_per_id, words_per_id,
241                num_nodes);
242
243         let entry = if oper.initial_value() { usize::MAX } else {0};
244
245         let zeroes = vec![0; num_nodes * words_per_id];
246         let gens = zeroes.clone();
247         let kills1 = zeroes.clone();
248         let kills2 = zeroes;
249         let on_entry = vec![entry; num_nodes * words_per_id];
250
251         let nodeid_to_index = build_nodeid_to_index(decl, cfg);
252
253         DataFlowContext {
254             tcx: tcx,
255             analysis_name: analysis_name,
256             words_per_id: words_per_id,
257             nodeid_to_index: nodeid_to_index,
258             bits_per_id: bits_per_id,
259             oper: oper,
260             gens: gens,
261             action_kills: kills1,
262             scope_kills: kills2,
263             on_entry: on_entry
264         }
265     }
266
267     pub fn add_gen(&mut self, id: ast::NodeId, bit: usize) {
268         //! Indicates that `id` generates `bit`
269         debug!("{} add_gen(id={}, bit={})",
270                self.analysis_name, id, bit);
271         assert!(self.nodeid_to_index.contains_key(&id));
272         assert!(self.bits_per_id > 0);
273
274         let indices = get_cfg_indices(id, &self.nodeid_to_index);
275         for &cfgidx in indices {
276             let (start, end) = self.compute_id_range(cfgidx);
277             let gens = &mut self.gens[start.. end];
278             set_bit(gens, bit);
279         }
280     }
281
282     pub fn add_kill(&mut self, kind: KillFrom, id: ast::NodeId, bit: usize) {
283         //! Indicates that `id` kills `bit`
284         debug!("{} add_kill(id={}, bit={})",
285                self.analysis_name, id, bit);
286         assert!(self.nodeid_to_index.contains_key(&id));
287         assert!(self.bits_per_id > 0);
288
289         let indices = get_cfg_indices(id, &self.nodeid_to_index);
290         for &cfgidx in indices {
291             let (start, end) = self.compute_id_range(cfgidx);
292             let kills = match kind {
293                 KillFrom::Execution => &mut self.action_kills[start.. end],
294                 KillFrom::ScopeEnd =>  &mut self.scope_kills[start.. end],
295             };
296             set_bit(kills, bit);
297         }
298     }
299
300     fn apply_gen_kill(&self, cfgidx: CFGIndex, bits: &mut [usize]) {
301         //! Applies the gen and kill sets for `cfgidx` to `bits`
302         debug!("{} apply_gen_kill(cfgidx={:?}, bits={}) [before]",
303                self.analysis_name, cfgidx, mut_bits_to_string(bits));
304         assert!(self.bits_per_id > 0);
305
306         let (start, end) = self.compute_id_range(cfgidx);
307         let gens = &self.gens[start.. end];
308         bitwise(bits, gens, &Union);
309         let kills = &self.action_kills[start.. end];
310         bitwise(bits, kills, &Subtract);
311         let kills = &self.scope_kills[start.. end];
312         bitwise(bits, kills, &Subtract);
313
314         debug!("{} apply_gen_kill(cfgidx={:?}, bits={}) [after]",
315                self.analysis_name, cfgidx, mut_bits_to_string(bits));
316     }
317
318     fn compute_id_range(&self, cfgidx: CFGIndex) -> (usize, usize) {
319         let n = cfgidx.node_id();
320         let start = n * self.words_per_id;
321         let end = start + self.words_per_id;
322
323         assert!(start < self.gens.len());
324         assert!(end <= self.gens.len());
325         assert!(self.gens.len() == self.action_kills.len());
326         assert!(self.gens.len() == self.scope_kills.len());
327         assert!(self.gens.len() == self.on_entry.len());
328
329         (start, end)
330     }
331
332
333     pub fn each_bit_on_entry<F>(&self, id: ast::NodeId, mut f: F) -> bool where
334         F: FnMut(usize) -> bool,
335     {
336         //! Iterates through each bit that is set on entry to `id`.
337         //! Only useful after `propagate()` has been called.
338         if !self.has_bitset_for_nodeid(id) {
339             return true;
340         }
341         let indices = get_cfg_indices(id, &self.nodeid_to_index);
342         for &cfgidx in indices {
343             if !self.each_bit_for_node(Entry, cfgidx, |i| f(i)) {
344                 return false;
345             }
346         }
347         return true;
348     }
349
350     pub fn each_bit_for_node<F>(&self, e: EntryOrExit, cfgidx: CFGIndex, f: F) -> bool where
351         F: FnMut(usize) -> bool,
352     {
353         //! Iterates through each bit that is set on entry/exit to `cfgidx`.
354         //! Only useful after `propagate()` has been called.
355
356         if self.bits_per_id == 0 {
357             // Skip the surprisingly common degenerate case.  (Note
358             // compute_id_range requires self.words_per_id > 0.)
359             return true;
360         }
361
362         let (start, end) = self.compute_id_range(cfgidx);
363         let on_entry = &self.on_entry[start.. end];
364         let temp_bits;
365         let slice = match e {
366             Entry => on_entry,
367             Exit => {
368                 let mut t = on_entry.to_vec();
369                 self.apply_gen_kill(cfgidx, &mut t);
370                 temp_bits = t;
371                 &temp_bits[..]
372             }
373         };
374         debug!("{} each_bit_for_node({:?}, cfgidx={:?}) bits={}",
375                self.analysis_name, e, cfgidx, bits_to_string(slice));
376         self.each_bit(slice, f)
377     }
378
379     pub fn each_gen_bit<F>(&self, id: ast::NodeId, mut f: F) -> bool where
380         F: FnMut(usize) -> bool,
381     {
382         //! Iterates through each bit in the gen set for `id`.
383         if !self.has_bitset_for_nodeid(id) {
384             return true;
385         }
386
387         if self.bits_per_id == 0 {
388             // Skip the surprisingly common degenerate case.  (Note
389             // compute_id_range requires self.words_per_id > 0.)
390             return true;
391         }
392
393         let indices = get_cfg_indices(id, &self.nodeid_to_index);
394         for &cfgidx in indices {
395             let (start, end) = self.compute_id_range(cfgidx);
396             let gens = &self.gens[start.. end];
397             debug!("{} each_gen_bit(id={}, gens={})",
398                    self.analysis_name, id, bits_to_string(gens));
399             if !self.each_bit(gens, |i| f(i)) {
400                 return false;
401             }
402         }
403         return true;
404     }
405
406     fn each_bit<F>(&self, words: &[usize], mut f: F) -> bool where
407         F: FnMut(usize) -> bool,
408     {
409         //! Helper for iterating over the bits in a bit set.
410         //! Returns false on the first call to `f` that returns false;
411         //! if all calls to `f` return true, then returns true.
412
413         for (word_index, &word) in words.iter().enumerate() {
414             if word != 0 {
415                 let base_index = word_index * usize::BITS;
416                 for offset in 0..usize::BITS {
417                     let bit = 1 << offset;
418                     if (word & bit) != 0 {
419                         // NB: we round up the total number of bits
420                         // that we store in any given bit set so that
421                         // it is an even multiple of usize::BITS.  This
422                         // means that there may be some stray bits at
423                         // the end that do not correspond to any
424                         // actual value.  So before we callback, check
425                         // whether the bit_index is greater than the
426                         // actual value the user specified and stop
427                         // iterating if so.
428                         let bit_index = base_index + offset as usize;
429                         if bit_index >= self.bits_per_id {
430                             return true;
431                         } else if !f(bit_index) {
432                             return false;
433                         }
434                     }
435                 }
436             }
437         }
438         return true;
439     }
440
441     pub fn add_kills_from_flow_exits(&mut self, cfg: &cfg::CFG) {
442         //! Whenever you have a `break` or `continue` statement, flow
443         //! exits through any number of enclosing scopes on its way to
444         //! the new destination. This function infers the kill bits of
445         //! those control operators based on the kill bits associated
446         //! with those scopes.
447         //!
448         //! This is usually called (if it is called at all), after
449         //! all add_gen and add_kill calls, but before propagate.
450
451         debug!("{} add_kills_from_flow_exits", self.analysis_name);
452         if self.bits_per_id == 0 {
453             // Skip the surprisingly common degenerate case.  (Note
454             // compute_id_range requires self.words_per_id > 0.)
455             return;
456         }
457         cfg.graph.each_edge(|_edge_index, edge| {
458             let flow_exit = edge.source();
459             let (start, end) = self.compute_id_range(flow_exit);
460             let mut orig_kills = self.scope_kills[start.. end].to_vec();
461
462             let mut changed = false;
463             for &node_id in &edge.data.exiting_scopes {
464                 let opt_cfg_idx = self.nodeid_to_index.get(&node_id);
465                 match opt_cfg_idx {
466                     Some(indices) => {
467                         for &cfg_idx in indices {
468                             let (start, end) = self.compute_id_range(cfg_idx);
469                             let kills = &self.scope_kills[start.. end];
470                             if bitwise(&mut orig_kills, kills, &Union) {
471                                 debug!("scope exits: scope id={} \
472                                         (node={:?} of {:?}) added killset: {}",
473                                        node_id, cfg_idx, indices,
474                                        bits_to_string(kills));
475                                 changed = true;
476                             }
477                         }
478                     }
479                     None => {
480                         debug!("{} add_kills_from_flow_exits flow_exit={:?} \
481                                 no cfg_idx for exiting_scope={}",
482                                self.analysis_name, flow_exit, node_id);
483                     }
484                 }
485             }
486
487             if changed {
488                 let bits = &mut self.scope_kills[start.. end];
489                 debug!("{} add_kills_from_flow_exits flow_exit={:?} bits={} [before]",
490                        self.analysis_name, flow_exit, mut_bits_to_string(bits));
491                 bits.clone_from_slice(&orig_kills[..]);
492                 debug!("{} add_kills_from_flow_exits flow_exit={:?} bits={} [after]",
493                        self.analysis_name, flow_exit, mut_bits_to_string(bits));
494             }
495             true
496         });
497     }
498 }
499
500 impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
501 //                                ^^^^^^^^^^^^^ only needed for pretty printing
502     pub fn propagate(&mut self, cfg: &cfg::CFG, blk: &hir::Block) {
503         //! Performs the data flow analysis.
504
505         if self.bits_per_id == 0 {
506             // Optimize the surprisingly common degenerate case.
507             return;
508         }
509
510         {
511             let words_per_id = self.words_per_id;
512             let mut propcx = PropagationContext {
513                 dfcx: &mut *self,
514                 changed: true
515             };
516
517             let mut temp = vec![0; words_per_id];
518             while propcx.changed {
519                 propcx.changed = false;
520                 propcx.reset(&mut temp);
521                 propcx.walk_cfg(cfg, &mut temp);
522             }
523         }
524
525         debug!("Dataflow result for {}:", self.analysis_name);
526         debug!("{}", {
527             let mut v = Vec::new();
528             self.pretty_print_to(box &mut v, blk).unwrap();
529             println!("{}", String::from_utf8(v).unwrap());
530             ""
531         });
532     }
533
534     fn pretty_print_to<'b>(&self, wr: Box<io::Write + 'b>,
535                            blk: &hir::Block) -> io::Result<()> {
536         let mut ps = pprust::rust_printer_annotated(wr, self, None);
537         try!(ps.cbox(pprust::indent_unit));
538         try!(ps.ibox(0));
539         try!(ps.print_block(blk));
540         pp::eof(&mut ps.s)
541     }
542 }
543
544 impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> {
545     fn walk_cfg(&mut self,
546                 cfg: &cfg::CFG,
547                 in_out: &mut [usize]) {
548         debug!("DataFlowContext::walk_cfg(in_out={}) {}",
549                bits_to_string(in_out), self.dfcx.analysis_name);
550         assert!(self.dfcx.bits_per_id > 0);
551
552         cfg.graph.each_node(|node_index, node| {
553             debug!("DataFlowContext::walk_cfg idx={:?} id={} begin in_out={}",
554                    node_index, node.data.id(), bits_to_string(in_out));
555
556             let (start, end) = self.dfcx.compute_id_range(node_index);
557
558             // Initialize local bitvector with state on-entry.
559             in_out.clone_from_slice(&self.dfcx.on_entry[start.. end]);
560
561             // Compute state on-exit by applying transfer function to
562             // state on-entry.
563             self.dfcx.apply_gen_kill(node_index, in_out);
564
565             // Propagate state on-exit from node into its successors.
566             self.propagate_bits_into_graph_successors_of(in_out, cfg, node_index);
567             true // continue to next node
568         });
569     }
570
571     fn reset(&mut self, bits: &mut [usize]) {
572         let e = if self.dfcx.oper.initial_value() {usize::MAX} else {0};
573         for b in bits {
574             *b = e;
575         }
576     }
577
578     fn propagate_bits_into_graph_successors_of(&mut self,
579                                                pred_bits: &[usize],
580                                                cfg: &cfg::CFG,
581                                                cfgidx: CFGIndex) {
582         for (_, edge) in cfg.graph.outgoing_edges(cfgidx) {
583             self.propagate_bits_into_entry_set_for(pred_bits, edge);
584         }
585     }
586
587     fn propagate_bits_into_entry_set_for(&mut self,
588                                          pred_bits: &[usize],
589                                          edge: &cfg::CFGEdge) {
590         let source = edge.source();
591         let cfgidx = edge.target();
592         debug!("{} propagate_bits_into_entry_set_for(pred_bits={}, {:?} to {:?})",
593                self.dfcx.analysis_name, bits_to_string(pred_bits), source, cfgidx);
594         assert!(self.dfcx.bits_per_id > 0);
595
596         let (start, end) = self.dfcx.compute_id_range(cfgidx);
597         let changed = {
598             // (scoping mutable borrow of self.dfcx.on_entry)
599             let on_entry = &mut self.dfcx.on_entry[start.. end];
600             bitwise(on_entry, pred_bits, &self.dfcx.oper)
601         };
602         if changed {
603             debug!("{} changed entry set for {:?} to {}",
604                    self.dfcx.analysis_name, cfgidx,
605                    bits_to_string(&self.dfcx.on_entry[start.. end]));
606             self.changed = true;
607         }
608     }
609 }
610
611 fn mut_bits_to_string(words: &mut [usize]) -> String {
612     bits_to_string(words)
613 }
614
615 fn bits_to_string(words: &[usize]) -> String {
616     let mut result = String::new();
617     let mut sep = '[';
618
619     // Note: this is a little endian printout of bytes.
620
621     for &word in words {
622         let mut v = word;
623         for _ in 0..usize::BYTES {
624             result.push(sep);
625             result.push_str(&format!("{:02x}", v & 0xFF));
626             v >>= 8;
627             sep = '-';
628         }
629     }
630     result.push(']');
631     return result
632 }
633
634 #[inline]
635 fn bitwise<Op:BitwiseOperator>(out_vec: &mut [usize],
636                                in_vec: &[usize],
637                                op: &Op) -> bool {
638     assert_eq!(out_vec.len(), in_vec.len());
639     let mut changed = false;
640     for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) {
641         let old_val = *out_elt;
642         let new_val = op.join(old_val, *in_elt);
643         *out_elt = new_val;
644         changed |= old_val != new_val;
645     }
646     changed
647 }
648
649 fn set_bit(words: &mut [usize], bit: usize) -> bool {
650     debug!("set_bit: words={} bit={}",
651            mut_bits_to_string(words), bit_str(bit));
652     let word = bit / usize::BITS;
653     let bit_in_word = bit % usize::BITS;
654     let bit_mask = 1 << bit_in_word;
655     debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, word);
656     let oldv = words[word];
657     let newv = oldv | bit_mask;
658     words[word] = newv;
659     oldv != newv
660 }
661
662 fn bit_str(bit: usize) -> String {
663     let byte = bit >> 8;
664     let lobits = 1 << (bit & 0xFF);
665     format!("[{}:{}-{:02x}]", bit, byte, lobits)
666 }
667
668 struct Union;
669 impl BitwiseOperator for Union {
670     fn join(&self, a: usize, b: usize) -> usize { a | b }
671 }
672 struct Subtract;
673 impl BitwiseOperator for Subtract {
674     fn join(&self, a: usize, b: usize) -> usize { a & !b }
675 }