do promote array indexing if we know it is in-bounds

This commit is contained in:
Ralf Jung 2021-01-06 20:03:22 +01:00
parent 69a997bef2
commit f62cecd807
6 changed files with 96 additions and 59 deletions

View File

@ -415,10 +415,11 @@ impl<'tcx> Validator<'_, 'tcx> {
// FIXME(eddyb) maybe cache this?
fn validate_local(&self, local: Local) -> Result<(), Unpromotable> {
if let TempState::Defined { location: loc, .. } = self.temps[local] {
let num_stmts = self.body[loc.block].statements.len();
let block = &self.body[loc.block];
let num_stmts = block.statements.len();
if loc.statement_index < num_stmts {
let statement = &self.body[loc.block].statements[loc.statement_index];
let statement = &block.statements[loc.statement_index];
match &statement.kind {
StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs),
_ => {
@ -430,7 +431,7 @@ impl<'tcx> Validator<'_, 'tcx> {
}
}
} else {
let terminator = self.body[loc.block].terminator();
let terminator = block.terminator();
match &terminator.kind {
TerminatorKind::Call { func, args, .. } => self.validate_call(func, args),
TerminatorKind::Yield { .. } => Err(Unpromotable),
@ -452,22 +453,15 @@ impl<'tcx> Validator<'_, 'tcx> {
match elem {
ProjectionElem::Deref => {
let mut promotable = false;
// The `is_empty` predicate is introduced to exclude the case
// where the projection operations are [ .field, * ].
// The reason is because promotion will be illegal if field
// accesses precede the dereferencing.
// We need to make sure this is a `Deref` of a local with no further projections.
// Discussion can be found at
// https://github.com/rust-lang/rust/pull/74945#discussion_r463063247
// There may be opportunity for generalization, but this needs to be
// accounted for.
if place_base.projection.is_empty() {
if let Some(local) = place_base.as_local() {
// This is a special treatment for cases like *&STATIC where STATIC is a
// global static variable.
// This pattern is generated only when global static variables are directly
// accessed and is qualified for promotion safely.
if let TempState::Defined { location, .. } =
self.temps[place_base.local]
{
if let TempState::Defined { location, .. } = self.temps[local] {
let def_stmt = self.body[location.block]
.statements
.get(location.statement_index);
@ -505,9 +499,49 @@ impl<'tcx> Validator<'_, 'tcx> {
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {}
ProjectionElem::Index(local) => {
// This could be OOB, so reject for implicit promotion.
if !self.explicit {
return Err(Unpromotable);
let mut promotable = false;
// Only accept if we can predict the index and are indexing an array.
let val = if let TempState::Defined { location: loc, .. } =
self.temps[local]
{
let block = &self.body[loc.block];
if loc.statement_index < block.statements.len() {
let statement = &block.statements[loc.statement_index];
match &statement.kind {
StatementKind::Assign(box (
_,
Rvalue::Use(Operand::Constant(c)),
)) => c.literal.try_eval_usize(self.tcx, self.param_env),
_ => None,
}
} else {
None
}
} else {
None
};
if let Some(idx) = val {
// Determine the type of the thing we are indexing.
let ty = place_base.ty(self.body, self.tcx).ty;
match ty.kind() {
ty::Array(_, len) => {
// It's an array; determine its length.
if let Some(len) =
len.try_eval_usize(self.tcx, self.param_env)
{
// If the index is in-bounds, go ahead.
if idx < len {
promotable = true;
}
}
}
_ => {}
}
}
if !promotable {
return Err(Unpromotable);
}
}
self.validate_local(local)?;
}

View File

@ -24,41 +24,41 @@ fn main() -> () {
}
alloc0 (static: FOO, size: 8, align: 4) {
alloc31 03 00 00 00 ....
alloc27 03 00 00 00 ....
}
alloc31 (size: 48, align: 4) {
0x00 00 00 00 00 __ __ __ __ alloc8 00 00 00 00 ........
0x10 00 00 00 00 __ __ __ __ alloc14 02 00 00 00 ........
0x20 01 00 00 00 2a 00 00 00 alloc29 03 00 00 00 ....*.......
alloc27 (size: 48, align: 4) {
0x00 00 00 00 00 __ __ __ __ alloc12 00 00 00 00 ........
0x10 00 00 00 00 __ __ __ __ alloc17 02 00 00 00 ........
0x20 01 00 00 00 2a 00 00 00 alloc25 03 00 00 00 ....*.......
}
alloc8 (size: 0, align: 4) {}
alloc12 (size: 0, align: 4) {}
alloc14 (size: 8, align: 4) {
alloc12 alloc13
alloc17 (size: 8, align: 4) {
alloc15 alloc16
}
alloc12 (size: 1, align: 1) {
alloc15 (size: 1, align: 1) {
05 .
}
alloc13 (size: 1, align: 1) {
alloc16 (size: 1, align: 1) {
06 .
}
alloc29 (size: 12, align: 4) {
a21+0x3 alloc23 a28+0x2
alloc25 (size: 12, align: 4) {
a21+0x3 alloc22 a24+0x2
}
alloc21 (size: 4, align: 1) {
2a 45 15 6f *E.o
}
alloc23 (size: 1, align: 1) {
alloc22 (size: 1, align: 1) {
2a *
}
alloc28 (size: 4, align: 1) {
alloc24 (size: 4, align: 1) {
2a 45 15 6f *E.o
}

View File

@ -24,44 +24,44 @@ fn main() -> () {
}
alloc0 (static: FOO, size: 16, align: 8) {
alloc31 03 00 00 00 00 00 00 00 ........
alloc27 03 00 00 00 00 00 00 00 ........
}
alloc31 (size: 72, align: 8) {
0x00 00 00 00 00 __ __ __ __ alloc8 ....
alloc27 (size: 72, align: 8) {
0x00 00 00 00 00 __ __ __ __ alloc12 ....
0x10 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ ............
0x20 alloc14 02 00 00 00 00 00 00 00 ........
0x30 01 00 00 00 2a 00 00 00 alloc29 ....*...
0x20 alloc17 02 00 00 00 00 00 00 00 ........
0x30 01 00 00 00 2a 00 00 00 alloc25 ....*...
0x40 03 00 00 00 00 00 00 00 ........
}
alloc8 (size: 0, align: 8) {}
alloc12 (size: 0, align: 8) {}
alloc14 (size: 16, align: 8) {
alloc12 alloc13
alloc17 (size: 16, align: 8) {
alloc15 alloc16
}
alloc12 (size: 1, align: 1) {
alloc15 (size: 1, align: 1) {
05 .
}
alloc13 (size: 1, align: 1) {
alloc16 (size: 1, align: 1) {
06 .
}
alloc29 (size: 24, align: 8) {
0x00 alloc21+0x3 alloc23
0x10 alloc28+0x2
alloc25 (size: 24, align: 8) {
0x00 alloc21+0x3 alloc22
0x10 alloc24+0x2
}
alloc21 (size: 4, align: 1) {
2a 45 15 6f *E.o
}
alloc23 (size: 1, align: 1) {
alloc22 (size: 1, align: 1) {
2a *
}
alloc28 (size: 4, align: 1) {
alloc24 (size: 4, align: 1) {
2a 45 15 6f *E.o
}

View File

@ -24,30 +24,30 @@ fn main() -> () {
}
alloc0 (static: FOO, size: 4, align: 4) {
alloc11
alloc10
}
alloc11 (size: 168, align: 1) {
alloc10 (size: 168, align: 1) {
0x00 ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ................
0x10 ab ab ab ab ab ab ab ab ab ab ab ab alloc4 ............
0x10 ab ab ab ab ab ab ab ab ab ab ab ab alloc5 ............
0x20 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x80 00 00 00 00 00 00 00 00 00 00 alloc6 00 00 ............
0x90 a9+0x63 00 00 00 00 00 00 00 00 00 00 00 00 ............
0x80 00 00 00 00 00 00 00 00 00 00 alloc7 00 00 ............
0x90 a8+0x63 00 00 00 00 00 00 00 00 00 00 00 00 ............
0xa0 00 00 00 00 00 00 00 00 ........
}
alloc4 (size: 4, align: 4) {
alloc5 (size: 4, align: 4) {
2a 00 00 00 *...
}
alloc6 (fn: main)
alloc7 (fn: main)
alloc9 (size: 100, align: 1) {
alloc8 (size: 100, align: 1) {
0x00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

View File

@ -24,12 +24,12 @@ fn main() -> () {
}
alloc0 (static: FOO, size: 8, align: 8) {
alloc11
alloc10
}
alloc11 (size: 180, align: 1) {
alloc10 (size: 180, align: 1) {
0x00 ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ................
0x10 ab ab ab ab ab ab ab ab ab ab ab ab alloc4 ............
0x10 ab ab ab ab ab ab ab ab ab ab ab ab alloc5 ............
0x20 01 ef cd ab 00 00 00 00 00 00 00 00 ............
0x30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
@ -37,18 +37,18 @@ alloc11 (size: 180, align: 1) {
0x60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..............
0x90 alloc6 00 00 alloc9+0x63 ..
0x90 alloc7 00 00 alloc8+0x63 ..
0xa0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0xb0 00 00 00 00 ....
}
alloc4 (size: 4, align: 4) {
alloc5 (size: 4, align: 4) {
2a 00 00 00 *...
}
alloc6 (fn: main)
alloc7 (fn: main)
alloc9 (size: 100, align: 1) {
alloc8 (size: 100, align: 1) {
0x00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

View File

@ -30,6 +30,9 @@ fn main() {
baz_i32(&(1/1));
baz_i32(&(1%1));
// in-bounds array access is okay
baz_i32(&([1,2,3][0] + 1));
// Top-level projections do not get promoted, so no error here.
if false {
#[allow(unconditional_panic)]