about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2021-01-06 20:03:22 +0100
committerRalf Jung <post@ralfj.de>2021-01-22 10:36:25 +0100
commitf62cecd80761ae3de9134c5a021bcaa4aed9337e (patch)
tree2078e9b05f5c8036da93f5f8c2ca5f188b3cfc66
parent69a997bef25e47ce0884a69a52a4120b0fe1b9c1 (diff)
downloadrust-f62cecd80761ae3de9134c5a021bcaa4aed9337e.tar.gz
rust-f62cecd80761ae3de9134c5a021bcaa4aed9337e.zip
do promote array indexing if we know it is in-bounds
-rw-r--r--compiler/rustc_mir/src/transform/promote_consts.rs64
-rw-r--r--src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir28
-rw-r--r--src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir30
-rw-r--r--src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir16
-rw-r--r--src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir14
-rw-r--r--src/test/ui/consts/promotion.rs3
6 files changed, 96 insertions, 59 deletions
diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs
index ce3e03e3c6d..d8758e04544 100644
--- a/compiler/rustc_mir/src/transform/promote_consts.rs
+++ b/compiler/rustc_mir/src/transform/promote_consts.rs
@@ -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)?;
                     }
diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir b/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
index 9fe3234f6ae..d2e764f856f 100644
--- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
+++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
@@ -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
 }
diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir b/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
index 3039f8ffab7..00bf91f90bf 100644
--- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
+++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
@@ -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
 }
diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir b/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
index cf7d82ef15e..519002da392 100644
--- a/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
+++ b/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
@@ -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 │ ................
diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir b/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
index f2227c40fcb..73c4288c32e 100644
--- a/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
+++ b/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
@@ -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 │ ................
diff --git a/src/test/ui/consts/promotion.rs b/src/test/ui/consts/promotion.rs
index 3d952964213..e7726dd0a4b 100644
--- a/src/test/ui/consts/promotion.rs
+++ b/src/test/ui/consts/promotion.rs
@@ -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)]