From 32cc106af3486a6f390b7428dfc2414e7cbccb0c Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 31 May 2023 23:58:20 -0700 Subject: [PATCH 1/5] Lower unchecked_{div, rem} to BinOp::{Div, Rem} --- .../src/lower_intrinsics.rs | 51 +++++++++------- ...r_intrinsics.align_of.LowerIntrinsics.diff | 2 +- ...wer_intrinsics.assume.LowerIntrinsics.diff | 2 +- ...trinsics.discriminant.LowerIntrinsics.diff | 14 ++--- ...f_copy_nonoverlapping.LowerIntrinsics.diff | 2 +- ...wer_intrinsics.forget.LowerIntrinsics.diff | 2 +- ..._intrinsics.non_const.LowerIntrinsics.diff | 2 +- ...insics.option_payload.LowerIntrinsics.diff | 4 +- ...intrinsics.ptr_offset.LowerIntrinsics.diff | 2 +- ...ad_via_copy_primitive.LowerIntrinsics.diff | 2 +- ..._via_copy_uninhabited.LowerIntrinsics.diff | 2 +- tests/mir-opt/lower_intrinsics.rs | 6 ++ ...er_intrinsics.size_of.LowerIntrinsics.diff | 2 +- ...s.transmute_inhabited.LowerIntrinsics.diff | 2 +- ...ics.transmute_ref_dst.LowerIntrinsics.diff | 2 +- ...te_to_box_uninhabited.LowerIntrinsics.diff | 2 +- ...te_to_mut_uninhabited.LowerIntrinsics.diff | 2 +- ...te_to_ref_uninhabited.LowerIntrinsics.diff | 2 +- ...transmute_uninhabited.LowerIntrinsics.diff | 2 +- ..._intrinsics.unchecked.LowerIntrinsics.diff | 60 +++++++++++++++++++ ...ntrinsics.unreachable.LowerIntrinsics.diff | 2 +- ...rinsics.with_overflow.LowerIntrinsics.diff | 6 +- ...write_via_move_string.LowerIntrinsics.diff | 2 +- 23 files changed, 123 insertions(+), 52 deletions(-) create mode 100644 tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.diff diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index dae01e41e5f3..3a7d58f71256 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 { diff --git a/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff index dd742d87a295..3530f4a807f2 100644 --- a/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff @@ -7,7 +7,7 @@ bb0: { - _0 = std::intrinsics::min_align_of::() -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:21:5: 21:40 +- // + span: $DIR/lower_intrinsics.rs:27:5: 27:40 - // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::min_align_of::}, val: Value() } + _0 = AlignOf(T); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42 diff --git a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff index e95c3f9bcc70..158ce62e209c 100644 --- a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff @@ -11,7 +11,7 @@ StorageLive(_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 - _1 = std::intrinsics::assume(const true) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:106:9: 106:32 +- // + span: $DIR/lower_intrinsics.rs:112:9: 112:32 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value() } + assume(const true); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 + goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 diff --git a/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff index 1f03b7b0baf4..6fc9616d8554 100644 --- a/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff @@ -31,7 +31,7 @@ _3 = &(*_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44 - _2 = discriminant_value::(move _3) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:82:5: 82:41 +- // + span: $DIR/lower_intrinsics.rs:88:5: 88:41 - // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a T) -> ::Discriminant {discriminant_value::}, val: Value() } + _2 = discriminant((*_3)); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 @@ -46,13 +46,13 @@ StorageLive(_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 _19 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:83:42: 83:44 + // + span: $DIR/lower_intrinsics.rs:89:42: 89:44 // + literal: Const { ty: &i32, val: Unevaluated(discriminant, [T], Some(promoted[2])) } _7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 _6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 - _5 = discriminant_value::(move _6) -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:83:5: 83:41 +- // + span: $DIR/lower_intrinsics.rs:89:5: 89:41 - // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a i32) -> ::Discriminant {discriminant_value::}, val: Value() } + _5 = discriminant((*_6)); // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 + goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 @@ -67,13 +67,13 @@ StorageLive(_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 _18 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:84:42: 84:45 + // + span: $DIR/lower_intrinsics.rs:90:42: 90:45 // + literal: Const { ty: &(), val: Unevaluated(discriminant, [T], Some(promoted[1])) } _11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 _10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 - _9 = discriminant_value::<()>(move _10) -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:84:5: 84:41 +- // + span: $DIR/lower_intrinsics.rs:90:5: 90:41 - // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value() } + _9 = discriminant((*_10)); // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 + goto -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 @@ -88,13 +88,13 @@ StorageLive(_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 _17 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:85:42: 85:47 + // + span: $DIR/lower_intrinsics.rs:91:42: 91:47 // + literal: Const { ty: &E, val: Unevaluated(discriminant, [T], Some(promoted[0])) } _15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 _14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 - _13 = discriminant_value::(move _14) -> [return: bb4, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:85:5: 85:41 +- // + span: $DIR/lower_intrinsics.rs:91:5: 91:41 - // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a E) -> ::Discriminant {discriminant_value::}, val: Value() } + _13 = discriminant((*_14)); // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 + goto -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 diff --git a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff index a54e9a9320ee..5b870ccf5ee2 100644 --- a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff @@ -49,7 +49,7 @@ StorageDead(_9); // scope 3 at $DIR/lower_intrinsics.rs:+4:90: +4:91 - _3 = copy_nonoverlapping::(move _4, move _8, const 0_usize) -> [return: bb1, unwind unreachable]; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:99:9: 99:28 +- // + span: $DIR/lower_intrinsics.rs:105:9: 105:28 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {copy_nonoverlapping::}, val: Value() } + copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 + goto -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 diff --git a/tests/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff index bfb000ccdb5c..582a79f48d8c 100644 --- a/tests/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff @@ -11,7 +11,7 @@ _2 = move _1; // scope 0 at $DIR/lower_intrinsics.rs:+1:30: +1:31 - _0 = std::intrinsics::forget::(move _2) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:26:5: 26:29 +- // + span: $DIR/lower_intrinsics.rs:32:5: 32:29 - // + literal: Const { ty: extern "rust-intrinsic" fn(T) {std::intrinsics::forget::}, val: Value() } + _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32 diff --git a/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff index 64d82907c7e3..81ad97077b42 100644 --- a/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff @@ -13,7 +13,7 @@ StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+2:9: +2:18 _1 = std::intrinsics::size_of::; // scope 0 at $DIR/lower_intrinsics.rs:+2:21: +2:51 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:37:21: 37:51 + // + span: $DIR/lower_intrinsics.rs:43:21: 43:51 // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}, val: Value() } StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:14 _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:14 diff --git a/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff index b022e2ba42bb..edc66e2c75ce 100644 --- a/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff @@ -24,7 +24,7 @@ _4 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:55: +2:56 - _3 = option_payload_ptr::(move _4) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:137:18: 137:54 +- // + span: $DIR/lower_intrinsics.rs:143:18: 143:54 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option) -> *const usize {option_payload_ptr::}, val: Value() } + _3 = &raw const (((*_4) as Some).0: usize); // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57 + goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57 @@ -37,7 +37,7 @@ _6 = &raw const (*_2); // scope 2 at $DIR/lower_intrinsics.rs:+3:55: +3:56 - _5 = option_payload_ptr::(move _6) -> [return: bb2, unwind unreachable]; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:138:18: 138:54 +- // + span: $DIR/lower_intrinsics.rs:144:18: 144:54 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option) -> *const String {option_payload_ptr::}, val: Value() } + _5 = &raw const (((*_6) as Some).0: std::string::String); // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57 + goto -> bb2; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57 diff --git a/tests/mir-opt/lower_intrinsics.ptr_offset.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.ptr_offset.LowerIntrinsics.diff index 60a1dd0ba7d0..1760efe77d98 100644 --- a/tests/mir-opt/lower_intrinsics.ptr_offset.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.ptr_offset.LowerIntrinsics.diff @@ -15,7 +15,7 @@ _4 = _2; // scope 0 at $DIR/lower_intrinsics.rs:+1:33: +1:34 - _0 = offset::<*const i32, isize>(move _3, move _4) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:35 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:144:5: 144:29 +- // + span: $DIR/lower_intrinsics.rs:150:5: 150:29 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, isize) -> *const i32 {offset::<*const i32, isize>}, val: Value() } + _0 = Offset(move _3, move _4); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:35 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:35 diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff index 5805df48f544..8583766348a6 100644 --- a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff @@ -13,7 +13,7 @@ _2 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47 - _0 = read_via_copy::(move _2) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:119:14: 119:45 +- // + span: $DIR/lower_intrinsics.rs:125:14: 125:45 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32) -> i32 {read_via_copy::}, val: Value() } + _0 = (*_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 + goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff index 95b2ec49d807..f64bc9dcf620 100644 --- a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff @@ -13,7 +13,7 @@ _2 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47 - _0 = read_via_copy::(move _2) -> unwind unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:124:14: 124:45 +- // + span: $DIR/lower_intrinsics.rs:130:14: 130:45 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Never) -> Never {read_via_copy::}, val: Value() } + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 } diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index 0ca88a42e3fd..30b5c78e647c 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs @@ -11,6 +11,12 @@ pub fn wrapping(a: i32, b: i32) { let _z = core::intrinsics::wrapping_mul(a, b); } +// EMIT_MIR lower_intrinsics.unchecked.LowerIntrinsics.diff +pub unsafe fn unchecked(a: i32, b: i32) { + let _x = core::intrinsics::unchecked_div(a, b); + let _y = core::intrinsics::unchecked_rem(a, b); +} + // EMIT_MIR lower_intrinsics.size_of.LowerIntrinsics.diff pub fn size_of() -> usize { core::intrinsics::size_of::() diff --git a/tests/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff index 27e8accea8be..a880df6a5c23 100644 --- a/tests/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff @@ -7,7 +7,7 @@ bb0: { - _0 = std::intrinsics::size_of::() -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:16:5: 16:35 +- // + span: $DIR/lower_intrinsics.rs:22:5: 22:35 - // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}, val: Value() } + _0 = SizeOf(T); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37 diff --git a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff index 1b3b7685185b..cde7c64c57a5 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff @@ -13,7 +13,7 @@ _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35 - _0 = transmute::(move _2) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:43:14: 43:33 +- // + span: $DIR/lower_intrinsics.rs:49:14: 49:33 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(std::cmp::Ordering) -> i8 {transmute::}, val: Value() } + _0 = move _2 as i8 (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 + goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 diff --git a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff index c6a7d2287e75..6fc0f3d3e3fe 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff @@ -13,7 +13,7 @@ _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35 - _0 = transmute::<&T, *const T>(move _2) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:53:14: 53:33 +- // + span: $DIR/lower_intrinsics.rs:59:14: 59:33 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&T) -> *const T {transmute::<&T, *const T>}, val: Value() } + _0 = move _2 as *const T (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 + goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff index aa5d9619d10a..e6887a382a2d 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff @@ -12,7 +12,7 @@ StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 - _1 = transmute::>(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:70:25: 70:44 +- // + span: $DIR/lower_intrinsics.rs:76:25: 76:44 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> Box {transmute::>}, val: Value() } + _1 = const 1_usize as std::boxed::Box (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff index 5fafd45fe852..b2a44b7c5611 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff @@ -12,7 +12,7 @@ StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 - _1 = transmute::(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:64:25: 64:44 +- // + span: $DIR/lower_intrinsics.rs:70:25: 70:44 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &mut Never {transmute::}, val: Value() } + _1 = const 1_usize as &mut Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff index 08dead132119..c49d3aeff70b 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff @@ -12,7 +12,7 @@ StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 - _1 = transmute::(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:58:21: 58:40 +- // + span: $DIR/lower_intrinsics.rs:64:21: 64:40 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &Never {transmute::}, val: Value() } + _1 = const 1_usize as &Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 diff --git a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff index f0b76127dd5e..06759d74a320 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff @@ -13,7 +13,7 @@ _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:47: +1:48 - _0 = transmute::<(), Never>(move _2) -> unwind unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:48:14: 48:46 +- // + span: $DIR/lower_intrinsics.rs:54:14: 54:46 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Never {transmute::<(), Never>}, val: Value() } + _0 = move _2 as Never (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49 + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49 diff --git a/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.diff new file mode 100644 index 000000000000..9bb43d850ebf --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.diff @@ -0,0 +1,60 @@ +- // MIR for `unchecked` before LowerIntrinsics ++ // MIR for `unchecked` after LowerIntrinsics + + fn unchecked(_1: i32, _2: i32) -> () { + debug a => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:25: +0:26 + debug b => _2; // in scope 0 at $DIR/lower_intrinsics.rs:+0:33: +0:34 + let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:41: +0:41 + let _3: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:11 + let mut _4: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+1:46: +1:47 + let mut _5: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+1:49: +1:50 + let mut _7: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+2:46: +2:47 + let mut _8: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+2:49: +2:50 + scope 1 { + debug _x => _3; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:11 + let _6: i32; // in scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:11 + scope 2 { + debug _y => _6; // in scope 2 at $DIR/lower_intrinsics.rs:+2:9: +2:11 + } + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:11 + StorageLive(_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:46: +1:47 + _4 = _1; // scope 0 at $DIR/lower_intrinsics.rs:+1:46: +1:47 + StorageLive(_5); // scope 0 at $DIR/lower_intrinsics.rs:+1:49: +1:50 + _5 = _2; // scope 0 at $DIR/lower_intrinsics.rs:+1:49: +1:50 +- _3 = unchecked_div::(move _4, move _5) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:51 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:16:14: 16:45 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(i32, i32) -> i32 {unchecked_div::}, val: Value() } ++ _3 = Div(move _4, move _5); // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:51 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:51 + } + + bb1: { + StorageDead(_5); // scope 0 at $DIR/lower_intrinsics.rs:+1:50: +1:51 + StorageDead(_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:50: +1:51 + StorageLive(_6); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:11 + StorageLive(_7); // scope 1 at $DIR/lower_intrinsics.rs:+2:46: +2:47 + _7 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+2:46: +2:47 + StorageLive(_8); // scope 1 at $DIR/lower_intrinsics.rs:+2:49: +2:50 + _8 = _2; // scope 1 at $DIR/lower_intrinsics.rs:+2:49: +2:50 +- _6 = unchecked_rem::(move _7, move _8) -> [return: bb2, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:51 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:17:14: 17:45 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(i32, i32) -> i32 {unchecked_rem::}, val: Value() } ++ _6 = Rem(move _7, move _8); // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:51 ++ goto -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:51 + } + + bb2: { + StorageDead(_8); // scope 1 at $DIR/lower_intrinsics.rs:+2:50: +2:51 + StorageDead(_7); // scope 1 at $DIR/lower_intrinsics.rs:+2:50: +2:51 + _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:+0:41: +3:2 + StorageDead(_6); // scope 1 at $DIR/lower_intrinsics.rs:+3:1: +3:2 + StorageDead(_3); // scope 0 at $DIR/lower_intrinsics.rs:+3:1: +3:2 + return; // scope 0 at $DIR/lower_intrinsics.rs:+3:2: +3:2 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff index 28e45909c337..83c9c508bc0b 100644 --- a/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff @@ -13,7 +13,7 @@ StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45 - _2 = std::intrinsics::unreachable() -> unwind unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:31:14: 31:43 +- // + span: $DIR/lower_intrinsics.rs:37:14: 37:43 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value() } + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45 } diff --git a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff index 9cf4fbb88f38..4ae4466a6003 100644 --- a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff @@ -32,7 +32,7 @@ _5 = _2; // scope 0 at $DIR/lower_intrinsics.rs:+1:53: +1:54 - _3 = add_with_overflow::(move _4, move _5) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:112:14: 112:49 +- // + span: $DIR/lower_intrinsics.rs:118:14: 118:49 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {add_with_overflow::}, val: Value() } + _3 = CheckedAdd(move _4, move _5); // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55 @@ -48,7 +48,7 @@ _8 = _2; // scope 1 at $DIR/lower_intrinsics.rs:+2:53: +2:54 - _6 = sub_with_overflow::(move _7, move _8) -> [return: bb2, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:113:14: 113:49 +- // + span: $DIR/lower_intrinsics.rs:119:14: 119:49 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {sub_with_overflow::}, val: Value() } + _6 = CheckedSub(move _7, move _8); // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55 + goto -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55 @@ -64,7 +64,7 @@ _11 = _2; // scope 2 at $DIR/lower_intrinsics.rs:+3:53: +3:54 - _9 = mul_with_overflow::(move _10, move _11) -> [return: bb3, unwind unreachable]; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:114:14: 114:49 +- // + span: $DIR/lower_intrinsics.rs:120:14: 120:49 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {mul_with_overflow::}, val: Value() } + _9 = CheckedMul(move _10, move _11); // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55 + goto -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55 diff --git a/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.diff index 38d99f661dc6..2eabd7f626b6 100644 --- a/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.diff @@ -17,7 +17,7 @@ _4 = move _2; // scope 1 at $DIR/lower_intrinsics.rs:+1:50: +1:51 - _0 = write_via_move::(move _3, move _4) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:52 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:129:14: 129:46 +- // + span: $DIR/lower_intrinsics.rs:135:14: 135:46 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*mut String, String) {write_via_move::}, val: Value() } + (*_3) = move _4; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:52 + goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:52 From bfb923326f8089b23cfd30fc1e963841ec83eb77 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 1 Jun 2023 00:01:25 -0700 Subject: [PATCH 2/5] remove unchecked_div/_rem from cg_cranelift --- compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 0a513b08b74f..1e83c30bd677 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!(), From dc353f13b83f37ce5576788246acc7a109c17171 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 1 Jun 2023 00:01:35 -0700 Subject: [PATCH 3/5] remove unchecked_div/_rem from cg_ssa --- compiler/rustc_codegen_ssa/src/mir/intrinsic.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 1479242f23a6..9ac2424e76be 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 { From 73f104b6d6d5ae058a06a0f8eec3f370093e91a4 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 1 Jun 2023 00:05:12 -0700 Subject: [PATCH 4/5] remove unchecked_div/_rem from ctfe --- compiler/rustc_const_eval/src/interpret/intrinsics.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index a77c699c22f7..a4b58c9849b8 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -233,9 +233,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 { @@ -244,8 +242,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)?; From adb37d4999cbb83bd670bb767b3c8d08e43e3c7c Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 1 Jun 2023 18:52:11 -0700 Subject: [PATCH 5/5] Clarify when MIR `Div`/`Rem` trigger UB --- compiler/rustc_middle/src/mir/syntax.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 3e474c1d377e..94a1e9ced772 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1272,13 +1272,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,