[MIR] Promote temps to alloca on multi-assignment

Fixes #31002
This commit is contained in:
Simonas Kazlauskas 2016-01-21 18:57:43 +02:00
parent c4c9628de7
commit e74aa2bdff
4 changed files with 44 additions and 9 deletions

View File

@ -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 {

View File

@ -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<usize> {
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<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 {
@ -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);
}

View File

@ -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)))

View File

@ -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);
}