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