Skip to content

Commit 34fd686

Browse files
committed
Auto merge of #33667 - pnkfelix:fixes-to-mir-dataflow, r=arielb1
Fixes to mir dataflow Fixes to mir dataflow This collects a bunch of changes to `rustc_borrowck::borrowck::dataflow` (which others have pointed out should probably migrate to some crate that isn't tied to the borrow-checker -- but I have not attempted that here, especially since there are competing approaches to dataflow that we should also evaluate). These changes: 1. Provide a family of related analyses: MovingOutStatements (which is what the old AST-based dataflo computed), as well as MaybeInitialized, MaybeUninitalized, and DefinitelyInitialized. * (The last two are actually inverses of each other; we should pick one and drop the other.) 2. Fix bugs in the pre-existing analysis implementation, which was untested and thus some obvious bugs went unnoticed, which brings us to the third point: 3. Add a unit test infrastructure for the MIR dataflow analysis. * The tests work by adding a new intrinsic that is able to query the analysis state for a particular expression (technically, a particular L-value). * See the examples in compile-fail/mir-dataflow/inits-1.rs and compile-fail/mir-dataflow/uninits-1.rs * These tests are only checking the results for MaybeInitialized, MaybeUninitalized, and DefinitelyInitialized; I am not sure if it will be feasible to generalize this testing strategy to the MovingOutStatements dataflow operator.
2 parents da66f2f + df5c116 commit 34fd686

File tree

22 files changed

+2464
-837
lines changed

22 files changed

+2464
-837
lines changed

src/libcore/intrinsics.rs

+10
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,16 @@ extern "rust-intrinsic" {
168168
pub fn atomic_singlethreadfence_rel();
169169
pub fn atomic_singlethreadfence_acqrel();
170170

171+
/// Magic intrinsic that derives its meaning from attributes
172+
/// attached to the function.
173+
///
174+
/// For example, dataflow uses this to inject static assertions so
175+
/// that `rustc_peek(potentially_uninitialized)` would actually
176+
/// double-check that dataflow did indeed compute that it is
177+
/// uninitialized at that point in the control flow.
178+
#[cfg(not(stage0))]
179+
pub fn rustc_peek<T>(_: T) -> T;
180+
171181
/// Aborts the execution of the process.
172182
pub fn abort() -> !;
173183

src/librustc/middle/dataflow.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -660,8 +660,8 @@ fn set_bit(words: &mut [usize], bit: usize) -> bool {
660660
}
661661

662662
fn bit_str(bit: usize) -> String {
663-
let byte = bit >> 8;
664-
let lobits = 1 << (bit & 0xFF);
663+
let byte = bit >> 3;
664+
let lobits = 1 << (bit & 0b111);
665665
format!("[{}:{}-{:02x}]", bit, byte, lobits)
666666
}
667667

src/librustc/mir/repr.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,8 @@ pub struct UpvarDecl {
226226
/// list of the `Mir`.
227227
///
228228
/// (We use a `u32` internally just to save memory.)
229-
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
229+
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
230+
RustcEncodable, RustcDecodable)]
230231
pub struct BasicBlock(u32);
231232

232233
impl BasicBlock {

src/librustc/mir/transform.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use ty::TyCtxt;
1818
use syntax::ast::NodeId;
1919

2020
/// Where a specific Mir comes from.
21-
#[derive(Copy, Clone)]
21+
#[derive(Debug, Copy, Clone)]
2222
pub enum MirSource {
2323
/// Functions and methods.
2424
Fn(NodeId),

src/librustc_borrowck/bitslice.rs

+60-22
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,27 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
// FIXME: move this to `rustc_data_structures` and potentially merge
12+
// with `bitvec` there.
13+
1114
use std::mem;
1215

13-
/// `BitSlice` provides helper methods for treating a `[usize]`
16+
pub type Word = usize;
17+
18+
/// `BitSlice` provides helper methods for treating a `[Word]`
1419
/// as a bitvector.
1520
pub trait BitSlice {
1621
fn clear_bit(&mut self, idx: usize) -> bool;
1722
fn set_bit(&mut self, idx: usize) -> bool;
1823
fn get_bit(&self, idx: usize) -> bool;
1924
}
2025

21-
impl BitSlice for [usize] {
26+
impl BitSlice for [Word] {
2227
/// Clears bit at `idx` to 0; returns true iff this changed `self.`
2328
fn clear_bit(&mut self, idx: usize) -> bool {
2429
let words = self;
2530
debug!("clear_bit: words={} idx={}",
26-
bits_to_string(words, words.len() * mem::size_of::<usize>()), bit_str(idx));
31+
bits_to_string(words, words.len() * mem::size_of::<Word>()), bit_str(idx));
2732
let BitLookup { word, bit_in_word, bit_mask } = bit_lookup(idx);
2833
debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask);
2934
let oldv = words[word];
@@ -36,7 +41,7 @@ impl BitSlice for [usize] {
3641
fn set_bit(&mut self, idx: usize) -> bool {
3742
let words = self;
3843
debug!("set_bit: words={} idx={}",
39-
bits_to_string(words, words.len() * mem::size_of::<usize>()), bit_str(idx));
44+
bits_to_string(words, words.len() * mem::size_of::<Word>()), bit_str(idx));
4045
let BitLookup { word, bit_in_word, bit_mask } = bit_lookup(idx);
4146
debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask);
4247
let oldv = words[word];
@@ -54,52 +59,85 @@ impl BitSlice for [usize] {
5459
}
5560

5661
struct BitLookup {
57-
/// An index of the word holding the bit in original `[usize]` of query.
62+
/// An index of the word holding the bit in original `[Word]` of query.
5863
word: usize,
5964
/// Index of the particular bit within the word holding the bit.
6065
bit_in_word: usize,
6166
/// Word with single 1-bit set corresponding to where the bit is located.
62-
bit_mask: usize,
67+
bit_mask: Word,
6368
}
6469

6570
#[inline]
6671
fn bit_lookup(bit: usize) -> BitLookup {
67-
let usize_bits = mem::size_of::<usize>() * 8;
68-
let word = bit / usize_bits;
69-
let bit_in_word = bit % usize_bits;
72+
let word_bits = mem::size_of::<Word>() * 8;
73+
let word = bit / word_bits;
74+
let bit_in_word = bit % word_bits;
7075
let bit_mask = 1 << bit_in_word;
7176
BitLookup { word: word, bit_in_word: bit_in_word, bit_mask: bit_mask }
7277
}
7378

7479

75-
fn bit_str(bit: usize) -> String {
76-
let byte = bit >> 8;
77-
let lobits = 1 << (bit & 0xFF);
80+
fn bit_str(bit: Word) -> String {
81+
let byte = bit >> 3;
82+
let lobits = 1 << (bit & 0b111);
7883
format!("[{}:{}-{:02x}]", bit, byte, lobits)
7984
}
8085

81-
pub fn bits_to_string(words: &[usize], bytes: usize) -> String {
86+
pub fn bits_to_string(words: &[Word], bits: usize) -> String {
8287
let mut result = String::new();
8388
let mut sep = '[';
8489

8590
// Note: this is a little endian printout of bytes.
8691

92+
// i tracks how many bits we have printed so far.
8793
let mut i = 0;
8894
for &word in words.iter() {
8995
let mut v = word;
90-
for _ in 0..mem::size_of::<usize>() {
91-
let byte = v & 0xFF;
92-
if i >= bytes {
93-
assert!(byte == 0);
94-
} else {
95-
result.push(sep);
96-
result.push_str(&format!("{:02x}", byte));
97-
}
96+
loop { // for each byte in `v`:
97+
let remain = bits - i;
98+
// If less than a byte remains, then mask just that many bits.
99+
let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF };
100+
assert!(mask <= 0xFF);
101+
let byte = v & mask;
102+
103+
result.push(sep);
104+
result.push_str(&format!("{:02x}", byte));
105+
106+
if remain <= 8 { break; }
98107
v >>= 8;
99-
i += 1;
108+
i += 8;
100109
sep = '-';
101110
}
102111
}
103112
result.push(']');
104113
return result
105114
}
115+
116+
#[inline]
117+
pub fn bitwise<Op:BitwiseOperator>(out_vec: &mut [usize],
118+
in_vec: &[usize],
119+
op: &Op) -> bool {
120+
assert_eq!(out_vec.len(), in_vec.len());
121+
let mut changed = false;
122+
for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) {
123+
let old_val = *out_elt;
124+
let new_val = op.join(old_val, *in_elt);
125+
*out_elt = new_val;
126+
changed |= old_val != new_val;
127+
}
128+
changed
129+
}
130+
131+
pub trait BitwiseOperator {
132+
/// Applies some bit-operation pointwise to each of the bits in the two inputs.
133+
fn join(&self, pred1: usize, pred2: usize) -> usize;
134+
}
135+
136+
pub struct Union;
137+
impl BitwiseOperator for Union {
138+
fn join(&self, a: usize, b: usize) -> usize { a | b }
139+
}
140+
pub struct Subtract;
141+
impl BitwiseOperator for Subtract {
142+
fn join(&self, a: usize, b: usize) -> usize { a & !b }
143+
}

0 commit comments

Comments
 (0)