Skip to content

Commit 1aa4dd0

Browse files
authored
Rollup merge of #46264 - scottmcm:mir-array-len, r=arielb1
InstCombine Len([_; N]) => const N in MIR A small opportunity I noticed in passing. Not super exciting on its own, but opens the door for a const propagation pass that could completely remove const bounds checks from arrays at MIR time, for example.
2 parents 788fed8 + 62391c8 commit 1aa4dd0

File tree

2 files changed

+58
-8
lines changed

2 files changed

+58
-8
lines changed

src/librustc_mir/transform/instcombine.rs

+25-8
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010

1111
//! Performs various peephole optimizations.
1212
13-
use rustc::mir::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue, Local};
13+
use rustc::mir::{Constant, Literal, Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue, Local};
1414
use rustc::mir::visit::{MutVisitor, Visitor};
15-
use rustc::ty::TyCtxt;
16-
use rustc::util::nodemap::FxHashSet;
15+
use rustc::ty::{TyCtxt, TypeVariants};
16+
use rustc::util::nodemap::{FxHashMap, FxHashSet};
1717
use rustc_data_structures::indexed_vec::Idx;
1818
use std::mem;
1919
use transform::{MirPass, MirSource};
@@ -44,11 +44,11 @@ impl MirPass for InstCombine {
4444
}
4545
}
4646

47-
pub struct InstCombineVisitor {
48-
optimizations: OptimizationList,
47+
pub struct InstCombineVisitor<'tcx> {
48+
optimizations: OptimizationList<'tcx>,
4949
}
5050

51-
impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor {
51+
impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
5252
fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
5353
if self.optimizations.and_stars.remove(&location) {
5454
debug!("Replacing `&*`: {:?}", rvalue);
@@ -62,6 +62,11 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor {
6262
*rvalue = Rvalue::Use(Operand::Consume(new_lvalue))
6363
}
6464

65+
if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) {
66+
debug!("Replacing `Len([_; N])`: {:?}", rvalue);
67+
*rvalue = Rvalue::Use(Operand::Constant(box constant));
68+
}
69+
6570
self.super_rvalue(rvalue, location)
6671
}
6772
}
@@ -70,7 +75,7 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor {
7075
struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> {
7176
mir: &'b Mir<'tcx>,
7277
tcx: TyCtxt<'a, 'tcx, 'tcx>,
73-
optimizations: OptimizationList,
78+
optimizations: OptimizationList<'tcx>,
7479
}
7580

7681
impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> {
@@ -93,11 +98,23 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> {
9398
}
9499
}
95100

101+
if let Rvalue::Len(ref lvalue) = *rvalue {
102+
let lvalue_ty = lvalue.ty(&self.mir.local_decls, self.tcx).to_ty(self.tcx);
103+
if let TypeVariants::TyArray(_, len) = lvalue_ty.sty {
104+
let span = self.mir.source_info(location).span;
105+
let ty = self.tcx.types.usize;
106+
let literal = Literal::Value { value: len };
107+
let constant = Constant { span, ty, literal };
108+
self.optimizations.arrays_lengths.insert(location, constant);
109+
}
110+
}
111+
96112
self.super_rvalue(rvalue, location)
97113
}
98114
}
99115

100116
#[derive(Default)]
101-
struct OptimizationList {
117+
struct OptimizationList<'tcx> {
102118
and_stars: FxHashSet<Location>,
119+
arrays_lengths: FxHashMap<Location, Constant<'tcx>>,
103120
}

src/test/mir-opt/combine_array_len.rs

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2017 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+
fn norm2(x: [f32; 2]) -> f32 {
12+
let a = x[0];
13+
let b = x[1];
14+
a*a + b*b
15+
}
16+
17+
fn main() {
18+
assert_eq!(norm2([3.0, 4.0]), 5.0*5.0);
19+
}
20+
21+
// END RUST SOURCE
22+
23+
// START rustc.norm2.InstCombine.before.mir
24+
// _5 = Len(_1);
25+
// ...
26+
// _10 = Len(_1);
27+
// END rustc.norm2.InstCombine.before.mir
28+
29+
// START rustc.norm2.InstCombine.after.mir
30+
// _5 = const 2usize;
31+
// ...
32+
// _10 = const 2usize;
33+
// END rustc.norm2.InstCombine.after.mir

0 commit comments

Comments
 (0)