Skip to content

Commit f62cecd

Browse files
committed
do promote array indexing if we know it is in-bounds
1 parent 69a997b commit f62cecd

6 files changed

+96
-59
lines changed

compiler/rustc_mir/src/transform/promote_consts.rs

+49-15
Original file line numberDiff line numberDiff line change
@@ -415,10 +415,11 @@ impl<'tcx> Validator<'_, 'tcx> {
415415
// FIXME(eddyb) maybe cache this?
416416
fn validate_local(&self, local: Local) -> Result<(), Unpromotable> {
417417
if let TempState::Defined { location: loc, .. } = self.temps[local] {
418-
let num_stmts = self.body[loc.block].statements.len();
418+
let block = &self.body[loc.block];
419+
let num_stmts = block.statements.len();
419420

420421
if loc.statement_index < num_stmts {
421-
let statement = &self.body[loc.block].statements[loc.statement_index];
422+
let statement = &block.statements[loc.statement_index];
422423
match &statement.kind {
423424
StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs),
424425
_ => {
@@ -430,7 +431,7 @@ impl<'tcx> Validator<'_, 'tcx> {
430431
}
431432
}
432433
} else {
433-
let terminator = self.body[loc.block].terminator();
434+
let terminator = block.terminator();
434435
match &terminator.kind {
435436
TerminatorKind::Call { func, args, .. } => self.validate_call(func, args),
436437
TerminatorKind::Yield { .. } => Err(Unpromotable),
@@ -452,22 +453,15 @@ impl<'tcx> Validator<'_, 'tcx> {
452453
match elem {
453454
ProjectionElem::Deref => {
454455
let mut promotable = false;
455-
// The `is_empty` predicate is introduced to exclude the case
456-
// where the projection operations are [ .field, * ].
457-
// The reason is because promotion will be illegal if field
458-
// accesses precede the dereferencing.
456+
// We need to make sure this is a `Deref` of a local with no further projections.
459457
// Discussion can be found at
460458
// https://github.com/rust-lang/rust/pull/74945#discussion_r463063247
461-
// There may be opportunity for generalization, but this needs to be
462-
// accounted for.
463-
if place_base.projection.is_empty() {
459+
if let Some(local) = place_base.as_local() {
464460
// This is a special treatment for cases like *&STATIC where STATIC is a
465461
// global static variable.
466462
// This pattern is generated only when global static variables are directly
467463
// accessed and is qualified for promotion safely.
468-
if let TempState::Defined { location, .. } =
469-
self.temps[place_base.local]
470-
{
464+
if let TempState::Defined { location, .. } = self.temps[local] {
471465
let def_stmt = self.body[location.block]
472466
.statements
473467
.get(location.statement_index);
@@ -505,9 +499,49 @@ impl<'tcx> Validator<'_, 'tcx> {
505499
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {}
506500

507501
ProjectionElem::Index(local) => {
508-
// This could be OOB, so reject for implicit promotion.
509502
if !self.explicit {
510-
return Err(Unpromotable);
503+
let mut promotable = false;
504+
// Only accept if we can predict the index and are indexing an array.
505+
let val = if let TempState::Defined { location: loc, .. } =
506+
self.temps[local]
507+
{
508+
let block = &self.body[loc.block];
509+
if loc.statement_index < block.statements.len() {
510+
let statement = &block.statements[loc.statement_index];
511+
match &statement.kind {
512+
StatementKind::Assign(box (
513+
_,
514+
Rvalue::Use(Operand::Constant(c)),
515+
)) => c.literal.try_eval_usize(self.tcx, self.param_env),
516+
_ => None,
517+
}
518+
} else {
519+
None
520+
}
521+
} else {
522+
None
523+
};
524+
if let Some(idx) = val {
525+
// Determine the type of the thing we are indexing.
526+
let ty = place_base.ty(self.body, self.tcx).ty;
527+
match ty.kind() {
528+
ty::Array(_, len) => {
529+
// It's an array; determine its length.
530+
if let Some(len) =
531+
len.try_eval_usize(self.tcx, self.param_env)
532+
{
533+
// If the index is in-bounds, go ahead.
534+
if idx < len {
535+
promotable = true;
536+
}
537+
}
538+
}
539+
_ => {}
540+
}
541+
}
542+
if !promotable {
543+
return Err(Unpromotable);
544+
}
511545
}
512546
self.validate_local(local)?;
513547
}

src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir

+14-14
Original file line numberDiff line numberDiff line change
@@ -24,41 +24,41 @@ fn main() -> () {
2424
}
2525

2626
alloc0 (static: FOO, size: 8, align: 4) {
27-
╾─alloc31─╼ 03 00 00 00 │ ╾──╼....
27+
╾─alloc27─╼ 03 00 00 00 │ ╾──╼....
2828
}
2929

30-
alloc31 (size: 48, align: 4) {
31-
0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 00 00 00 00 │ ....░░░░╾──╼....
32-
0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc14─╼ 02 00 00 00 │ ....░░░░╾──╼....
33-
0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc29─╼ 03 00 00 00 │ ....*...╾──╼....
30+
alloc27 (size: 48, align: 4) {
31+
0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc12─╼ 00 00 00 00 │ ....░░░░╾──╼....
32+
0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc17─╼ 02 00 00 00 │ ....░░░░╾──╼....
33+
0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc25─╼ 03 00 00 00 │ ....*...╾──╼....
3434
}
3535

36-
alloc8 (size: 0, align: 4) {}
36+
alloc12 (size: 0, align: 4) {}
3737

38-
alloc14 (size: 8, align: 4) {
39-
╾─alloc12─╼ ╾─alloc13─╼ │ ╾──╼╾──╼
38+
alloc17 (size: 8, align: 4) {
39+
╾─alloc15─╼ ╾─alloc16─╼ │ ╾──╼╾──╼
4040
}
4141

42-
alloc12 (size: 1, align: 1) {
42+
alloc15 (size: 1, align: 1) {
4343
05 │ .
4444
}
4545

46-
alloc13 (size: 1, align: 1) {
46+
alloc16 (size: 1, align: 1) {
4747
06 │ .
4848
}
4949

50-
alloc29 (size: 12, align: 4) {
51-
╾─a21+0x3─╼ ╾─alloc23─╼ ╾─a28+0x2─╼ │ ╾──╼╾──╼╾──╼
50+
alloc25 (size: 12, align: 4) {
51+
╾─a21+0x3─╼ ╾─alloc22─╼ ╾─a24+0x2─╼ │ ╾──╼╾──╼╾──╼
5252
}
5353

5454
alloc21 (size: 4, align: 1) {
5555
2a 45 15 6f │ *E.o
5656
}
5757

58-
alloc23 (size: 1, align: 1) {
58+
alloc22 (size: 1, align: 1) {
5959
2a │ *
6060
}
6161

62-
alloc28 (size: 4, align: 1) {
62+
alloc24 (size: 4, align: 1) {
6363
2a 45 15 6f │ *E.o
6464
}

src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir

+15-15
Original file line numberDiff line numberDiff line change
@@ -24,44 +24,44 @@ fn main() -> () {
2424
}
2525

2626
alloc0 (static: FOO, size: 16, align: 8) {
27-
╾───────alloc31───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
27+
╾───────alloc27───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
2828
}
2929

30-
alloc31 (size: 72, align: 8) {
31-
0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc8────────╼ │ ....░░░░╾──────╼
30+
alloc27 (size: 72, align: 8) {
31+
0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc12───────╼ │ ....░░░░╾──────╼
3232
0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
33-
0x20 │ ╾───────alloc14───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
34-
0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc29───────╼ │ ....*...╾──────╼
33+
0x20 │ ╾───────alloc17───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
34+
0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc25───────╼ │ ....*...╾──────╼
3535
0x40 │ 03 00 00 00 00 00 00 00 │ ........
3636
}
3737

38-
alloc8 (size: 0, align: 8) {}
38+
alloc12 (size: 0, align: 8) {}
3939

40-
alloc14 (size: 16, align: 8) {
41-
╾───────alloc12───────╼ ╾───────alloc13───────╼ │ ╾──────╼╾──────╼
40+
alloc17 (size: 16, align: 8) {
41+
╾───────alloc15───────╼ ╾───────alloc16───────╼ │ ╾──────╼╾──────╼
4242
}
4343

44-
alloc12 (size: 1, align: 1) {
44+
alloc15 (size: 1, align: 1) {
4545
05 │ .
4646
}
4747

48-
alloc13 (size: 1, align: 1) {
48+
alloc16 (size: 1, align: 1) {
4949
06 │ .
5050
}
5151

52-
alloc29 (size: 24, align: 8) {
53-
0x00 │ ╾─────alloc21+0x3─────╼ ╾───────alloc23───────╼ │ ╾──────╼╾──────╼
54-
0x10 │ ╾─────alloc28+0x2─────╼ │ ╾──────╼
52+
alloc25 (size: 24, align: 8) {
53+
0x00 │ ╾─────alloc21+0x3─────╼ ╾───────alloc22───────╼ │ ╾──────╼╾──────╼
54+
0x10 │ ╾─────alloc24+0x2─────╼ │ ╾──────╼
5555
}
5656

5757
alloc21 (size: 4, align: 1) {
5858
2a 45 15 6f │ *E.o
5959
}
6060

61-
alloc23 (size: 1, align: 1) {
61+
alloc22 (size: 1, align: 1) {
6262
2a │ *
6363
}
6464

65-
alloc28 (size: 4, align: 1) {
65+
alloc24 (size: 4, align: 1) {
6666
2a 45 15 6f │ *E.o
6767
}

src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir

+8-8
Original file line numberDiff line numberDiff line change
@@ -24,30 +24,30 @@ fn main() -> () {
2424
}
2525

2626
alloc0 (static: FOO, size: 4, align: 4) {
27-
╾─alloc11─╼ │ ╾──╼
27+
╾─alloc10─╼ │ ╾──╼
2828
}
2929

30-
alloc11 (size: 168, align: 1) {
30+
alloc10 (size: 168, align: 1) {
3131
0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................
32-
0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc4──╼ │ ............╾──╼
32+
0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc5──╼ │ ............╾──╼
3333
0x20 │ 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3434
0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3535
0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3636
0x50 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3737
0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3838
0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
39-
0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾─alloc6──╼ 00 00 │ ..........╾──╼..
40-
0x90 │ ╾─a9+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............
39+
0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾─alloc7──╼ 00 00 │ ..........╾──╼..
40+
0x90 │ ╾─a8+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............
4141
0xa0 │ 00 00 00 00 00 00 00 00 │ ........
4242
}
4343

44-
alloc4 (size: 4, align: 4) {
44+
alloc5 (size: 4, align: 4) {
4545
2a 00 00 00 │ *...
4646
}
4747

48-
alloc6 (fn: main)
48+
alloc7 (fn: main)
4949

50-
alloc9 (size: 100, align: 1) {
50+
alloc8 (size: 100, align: 1) {
5151
0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
5252
0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
5353
0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................

src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir

+7-7
Original file line numberDiff line numberDiff line change
@@ -24,31 +24,31 @@ fn main() -> () {
2424
}
2525

2626
alloc0 (static: FOO, size: 8, align: 8) {
27-
╾───────alloc11───────╼ │ ╾──────╼
27+
╾───────alloc10───────╼ │ ╾──────╼
2828
}
2929

30-
alloc11 (size: 180, align: 1) {
30+
alloc10 (size: 180, align: 1) {
3131
0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................
32-
0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc4── │ ............╾───
32+
0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc5── │ ............╾───
3333
0x20 │ ──────────╼ 01 ef cd ab 00 00 00 00 00 00 00 00 │ ───╼............
3434
0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3535
0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3636
0x50 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3737
0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3838
0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3939
0x80 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ╾──── │ ..............╾─
40-
0x90 │ ─────alloc6─────╼ 00 00 ╾─────alloc9+0x63─────╼ │ ─────╼..╾──────╼
40+
0x90 │ ─────alloc7─────╼ 00 00 ╾─────alloc8+0x63─────╼ │ ─────╼..╾──────╼
4141
0xa0 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
4242
0xb0 │ 00 00 00 00 │ ....
4343
}
4444

45-
alloc4 (size: 4, align: 4) {
45+
alloc5 (size: 4, align: 4) {
4646
2a 00 00 00 │ *...
4747
}
4848

49-
alloc6 (fn: main)
49+
alloc7 (fn: main)
5050

51-
alloc9 (size: 100, align: 1) {
51+
alloc8 (size: 100, align: 1) {
5252
0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
5353
0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
5454
0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................

src/test/ui/consts/promotion.rs

+3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ fn main() {
3030
baz_i32(&(1/1));
3131
baz_i32(&(1%1));
3232

33+
// in-bounds array access is okay
34+
baz_i32(&([1,2,3][0] + 1));
35+
3336
// Top-level projections do not get promoted, so no error here.
3437
if false {
3538
#[allow(unconditional_panic)]

0 commit comments

Comments
 (0)