about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-06-02 16:02:06 -0700
committerGitHub <noreply@github.com>2023-06-02 16:02:06 -0700
commit5460f92a0f97238e87fef281134b08deb2f587ee (patch)
treecb108b149eb72261ac2ddd42adc1e42b4f82bb8b /compiler
parentdd09f4d35c5b6881f0eb757b5fd8c1604be3b06a (diff)
parentadb37d4999cbb83bd670bb767b3c8d08e43e3c7c (diff)
downloadrust-5460f92a0f97238e87fef281134b08deb2f587ee.tar.gz
rust-5460f92a0f97238e87fef281134b08deb2f587ee.zip
Rollup merge of #112168 - scottmcm:lower-div-rem-unchecked-to-mir, r=oli-obk
Lower `unchecked_div`/`_rem` to MIR's `BinOp::Div`/`Rem`

As described in <https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.BinOp.html#variant.Div>, the ordinary `BinOp`s for these are already UB for division by zero ([or overflow](https://llvm.org/docs/LangRef.html#sdiv-instruction), [demo](https://rust.godbolt.org/z/71e7P7Exh)), as MIR building is responsible for inserting code to panic for those cases regardless of whether the overflow checks are enabled.

So we can lower these in the same arm that lowers `wrapping_add` to MIR `BinOp::Add` and such, as all these cases turn into ordinary `Rvalue::BinaryOp`s.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs16
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs6
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs13
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs51
5 files changed, 39 insertions, 52 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 0a513b08b74..1e83c30bd67 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -475,9 +475,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
         sym::unchecked_add
         | sym::unchecked_sub
         | sym::unchecked_mul
-        | sym::unchecked_div
         | sym::exact_div
-        | sym::unchecked_rem
         | sym::unchecked_shl
         | sym::unchecked_shr => {
             intrinsic_args!(fx, args => (x, y); intrinsic);
@@ -487,8 +485,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 sym::unchecked_add => BinOp::Add,
                 sym::unchecked_sub => BinOp::Sub,
                 sym::unchecked_mul => BinOp::Mul,
-                sym::unchecked_div | sym::exact_div => BinOp::Div,
-                sym::unchecked_rem => BinOp::Rem,
+                sym::exact_div => BinOp::Div,
                 sym::unchecked_shl => BinOp::Shl,
                 sym::unchecked_shr => BinOp::Shr,
                 _ => unreachable!(),
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 1479242f23a..9ac2424e76b 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -211,8 +211,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 args[1].val.unaligned_volatile_store(bx, dst);
                 return;
             }
-            | sym::unchecked_div
-            | sym::unchecked_rem
             | sym::unchecked_shl
             | sym::unchecked_shr
             | sym::unchecked_add
@@ -229,20 +227,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                 bx.exactudiv(args[0].immediate(), args[1].immediate())
                             }
                         }
-                        sym::unchecked_div => {
-                            if signed {
-                                bx.sdiv(args[0].immediate(), args[1].immediate())
-                            } else {
-                                bx.udiv(args[0].immediate(), args[1].immediate())
-                            }
-                        }
-                        sym::unchecked_rem => {
-                            if signed {
-                                bx.srem(args[0].immediate(), args[1].immediate())
-                            } else {
-                                bx.urem(args[0].immediate(), args[1].immediate())
-                            }
-                        }
                         sym::unchecked_shl => bx.shl(args[0].immediate(), args[1].immediate()),
                         sym::unchecked_shr => {
                             if signed {
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index fb24cf48a9a..fffb9a7f264 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -238,9 +238,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             | sym::unchecked_shr
             | sym::unchecked_add
             | sym::unchecked_sub
-            | sym::unchecked_mul
-            | sym::unchecked_div
-            | sym::unchecked_rem => {
+            | sym::unchecked_mul => {
                 let l = self.read_immediate(&args[0])?;
                 let r = self.read_immediate(&args[1])?;
                 let bin_op = match intrinsic_name {
@@ -249,8 +247,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     sym::unchecked_add => BinOp::Add,
                     sym::unchecked_sub => BinOp::Sub,
                     sym::unchecked_mul => BinOp::Mul,
-                    sym::unchecked_div => BinOp::Div,
-                    sym::unchecked_rem => BinOp::Rem,
                     _ => bug!(),
                 };
                 let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, &l, &r)?;
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 83f8f00d72c..1a65f74f4fe 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1273,13 +1273,18 @@ pub enum BinOp {
     Mul,
     /// The `/` operator (division)
     ///
-    /// Division by zero is UB, because the compiler should have inserted checks
-    /// prior to this.
+    /// For integer types, division by zero is UB, as is `MIN / -1` for signed.
+    /// The compiler should have inserted checks prior to this.
+    ///
+    /// Floating-point division by zero is safe, and does not need guards.
     Div,
     /// The `%` operator (modulus)
     ///
-    /// Using zero as the modulus (second operand) is UB, because the compiler
-    /// should have inserted checks prior to this.
+    /// For integer types, using zero as the modulus (second operand) is UB,
+    /// as is `MIN % -1` for signed.
+    /// The compiler should have inserted checks prior to this.
+    ///
+    /// Floating-point remainder by zero is safe, and does not need guards.
     Rem,
     /// The `^` operator (bitwise xor)
     BitXor,
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index dae01e41e5f..3a7d58f7125 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -82,30 +82,35 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
                         drop(args);
                         terminator.kind = TerminatorKind::Goto { target };
                     }
-                    sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => {
-                        if let Some(target) = *target {
-                            let lhs;
-                            let rhs;
-                            {
-                                let mut args = args.drain(..);
-                                lhs = args.next().unwrap();
-                                rhs = args.next().unwrap();
-                            }
-                            let bin_op = match intrinsic_name {
-                                sym::wrapping_add => BinOp::Add,
-                                sym::wrapping_sub => BinOp::Sub,
-                                sym::wrapping_mul => BinOp::Mul,
-                                _ => bug!("unexpected intrinsic"),
-                            };
-                            block.statements.push(Statement {
-                                source_info: terminator.source_info,
-                                kind: StatementKind::Assign(Box::new((
-                                    *destination,
-                                    Rvalue::BinaryOp(bin_op, Box::new((lhs, rhs))),
-                                ))),
-                            });
-                            terminator.kind = TerminatorKind::Goto { target };
+                    sym::wrapping_add
+                    | sym::wrapping_sub
+                    | sym::wrapping_mul
+                    | sym::unchecked_div
+                    | sym::unchecked_rem => {
+                        let target = target.unwrap();
+                        let lhs;
+                        let rhs;
+                        {
+                            let mut args = args.drain(..);
+                            lhs = args.next().unwrap();
+                            rhs = args.next().unwrap();
                         }
+                        let bin_op = match intrinsic_name {
+                            sym::wrapping_add => BinOp::Add,
+                            sym::wrapping_sub => BinOp::Sub,
+                            sym::wrapping_mul => BinOp::Mul,
+                            sym::unchecked_div => BinOp::Div,
+                            sym::unchecked_rem => BinOp::Rem,
+                            _ => bug!("unexpected intrinsic"),
+                        };
+                        block.statements.push(Statement {
+                            source_info: terminator.source_info,
+                            kind: StatementKind::Assign(Box::new((
+                                *destination,
+                                Rvalue::BinaryOp(bin_op, Box::new((lhs, rhs))),
+                            ))),
+                        });
+                        terminator.kind = TerminatorKind::Goto { target };
                     }
                     sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
                         if let Some(target) = *target {