diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index f26307fd8c58e..70f50b4c042b1 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -24,12 +24,14 @@ impl BitVector { (self.data[word] & mask) != 0 } + /// Returns true if the bit has changed. pub fn insert(&mut self, bit: usize) -> bool { let (word, mask) = word_mask(bit); let data = &mut self.data[word]; let value = *data; - *data = value | mask; - (value | mask) != value + let new_value = value | mask; + *data = new_value; + new_value != value } pub fn insert_all(&mut self, all: &BitVector) -> bool { diff --git a/src/librustc_trans/trans/mir/analyze.rs b/src/librustc_trans/trans/mir/analyze.rs index 9d4c7663cb0d3..23cca55e4d480 100644 --- a/src/librustc_trans/trans/mir/analyze.rs +++ b/src/librustc_trans/trans/mir/analyze.rs @@ -11,7 +11,7 @@ //! An analysis to determine which temporaries require allocas and //! which do not. -use rustc_data_structures::fnv::FnvHashSet; +use rustc_data_structures::bitvec::BitVector; use rustc::mir::repr as mir; use rustc::mir::visit::{Visitor, LvalueContext}; use trans::common::{self, Block}; @@ -19,8 +19,8 @@ use super::rvalue; pub fn lvalue_temps<'bcx,'tcx>(bcx: Block<'bcx,'tcx>, mir: &mir::Mir<'tcx>) - -> FnvHashSet { - let mut analyzer = TempAnalyzer::new(); + -> BitVector { + let mut analyzer = TempAnalyzer::new(mir.temp_decls.len()); analyzer.visit_mir(mir); @@ -51,18 +51,28 @@ pub fn lvalue_temps<'bcx,'tcx>(bcx: Block<'bcx,'tcx>, } struct TempAnalyzer { - lvalue_temps: FnvHashSet, + lvalue_temps: BitVector, + seen_assigned: BitVector } impl TempAnalyzer { - fn new() -> TempAnalyzer { - TempAnalyzer { lvalue_temps: FnvHashSet() } + fn new(temp_count: usize) -> TempAnalyzer { + TempAnalyzer { + lvalue_temps: BitVector::new(temp_count), + seen_assigned: BitVector::new(temp_count) + } } fn mark_as_lvalue(&mut self, temp: usize) { debug!("marking temp {} as lvalue", temp); self.lvalue_temps.insert(temp); } + + fn mark_assigned(&mut self, temp: usize) { + if !self.seen_assigned.insert(temp) { + self.mark_as_lvalue(temp); + } + } } impl<'tcx> Visitor<'tcx> for TempAnalyzer { @@ -74,6 +84,7 @@ impl<'tcx> Visitor<'tcx> for TempAnalyzer { match *lvalue { mir::Lvalue::Temp(index) => { + self.mark_assigned(index as usize); if !rvalue::rvalue_creates_operand(rvalue) { self.mark_as_lvalue(index as usize); } diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs index 75ce33da2c9b9..cdde4cbb28604 100644 --- a/src/librustc_trans/trans/mir/mod.rs +++ b/src/librustc_trans/trans/mir/mod.rs @@ -97,7 +97,7 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) { let temps = mir.temp_decls.iter() .map(|decl| bcx.monomorphize(&decl.ty)) .enumerate() - .map(|(i, mty)| if lvalue_temps.contains(&i) { + .map(|(i, mty)| if lvalue_temps.contains(i) { TempRef::Lvalue(LvalueRef::alloca(bcx, mty, &format!("temp{:?}", i))) diff --git a/src/test/run-pass/mir_temp_promotions.rs b/src/test/run-pass/mir_temp_promotions.rs new file mode 100644 index 0000000000000..de83c1f5ee0cd --- /dev/null +++ b/src/test/run-pass/mir_temp_promotions.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_attrs)] + +#[rustc_mir] +fn test1(f: f32) -> bool { + // test that we properly promote temporaries to allocas when a temporary is assigned to + // multiple times (assignment is still happening once ∀ possible dataflows). + !(f.is_nan() || f.is_infinite()) +} + +fn main() { + assert_eq!(test1(0.0), true); +}