Skip to content

Commit

Permalink
[MIR] Promote temps to alloca on multi-assignment
Browse files Browse the repository at this point in the history
Fixes #31002
  • Loading branch information
nagisa committed Jan 21, 2016
1 parent c4c9628 commit e74aa2b
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 9 deletions.
6 changes: 4 additions & 2 deletions src/librustc_data_structures/bitvec.rs
Expand Up @@ -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 {
Expand Down
23 changes: 17 additions & 6 deletions src/librustc_trans/trans/mir/analyze.rs
Expand Up @@ -11,16 +11,16 @@
//! 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};
use super::rvalue;

pub fn lvalue_temps<'bcx,'tcx>(bcx: Block<'bcx,'tcx>,
mir: &mir::Mir<'tcx>)
-> FnvHashSet<usize> {
let mut analyzer = TempAnalyzer::new();
-> BitVector {
let mut analyzer = TempAnalyzer::new(mir.temp_decls.len());

analyzer.visit_mir(mir);

Expand Down Expand Up @@ -51,18 +51,28 @@ pub fn lvalue_temps<'bcx,'tcx>(bcx: Block<'bcx,'tcx>,
}

struct TempAnalyzer {
lvalue_temps: FnvHashSet<usize>,
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 {
Expand All @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/mir/mod.rs
Expand Up @@ -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)))
Expand Down
22 changes: 22 additions & 0 deletions 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}

0 comments on commit e74aa2b

Please sign in to comment.