From 05a665f21a6f9763d136a9d2d7c0255de6d333fb Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 25 Apr 2023 12:10:55 -0700 Subject: [PATCH] Lower `intrinsics::offset` to `mir::BinOp::Offset` They're semantically the same, so this means the backends don't need to handle the intrinsic and means fewer MIR basic blocks in pointer arithmetic code. --- .../src/intrinsics/mod.rs | 2 +- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 7 ----- .../src/const_eval/machine.rs | 17 ++++++++--- .../src/interpret/intrinsics.rs | 8 ----- .../src/lower_intrinsics.rs | 17 +++++++++++ ...intrinsics.ptr_offset.LowerIntrinsics.diff | 30 +++++++++++++++++++ tests/mir-opt/lower_intrinsics.rs | 5 ++++ 7 files changed, 66 insertions(+), 20 deletions(-) create mode 100644 tests/mir-opt/lower_intrinsics.ptr_offset.LowerIntrinsics.diff diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 03f2a65fcca..90b36c61114 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -534,7 +534,7 @@ fn codegen_regular_intrinsic_call<'tcx>( // The only difference between offset and arith_offset is regarding UB. Because Cranelift // doesn't have UB both are codegen'ed the same way - sym::offset | sym::arith_offset => { + sym::arith_offset => { intrinsic_args!(fx, args => (base, offset); intrinsic); let offset = offset.load_scalar(fx); diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 7af7fc92dbc..1479242f23a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -135,13 +135,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .unwrap(); OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx) } - sym::offset => { - let ty = substs.type_at(0); - let layout = bx.layout_of(ty); - let ptr = args[0].immediate(); - let offset = args[1].immediate(); - bx.inbounds_gep(bx.backend_type(layout), ptr, &[offset]) - } sym::arith_offset => { let ty = substs.type_at(0); let layout = bx.layout_of(ty); diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 814b67b46ec..bfca58a15b3 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -559,11 +559,20 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } fn binary_ptr_op( - _ecx: &InterpCx<'mir, 'tcx, Self>, - _bin_op: mir::BinOp, - _left: &ImmTy<'tcx>, - _right: &ImmTy<'tcx>, + ecx: &InterpCx<'mir, 'tcx, Self>, + bin_op: mir::BinOp, + left: &ImmTy<'tcx>, + right: &ImmTy<'tcx>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + if bin_op == mir::BinOp::Offset { + let ptr = left.to_scalar().to_pointer(ecx)?; + let offset_count = right.to_scalar().to_target_isize(ecx)?; + let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; + + let offset_ptr = ecx.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?; + return Ok((Scalar::from_maybe_pointer(offset_ptr, ecx), false, left.layout.ty)); + } + throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time"); } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index eada75ae391..a77c699c22f 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -286,14 +286,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::write_bytes => { self.write_bytes_intrinsic(&args[0], &args[1], &args[2])?; } - sym::offset => { - let ptr = self.read_pointer(&args[0])?; - let offset_count = self.read_target_isize(&args[1])?; - let pointee_ty = substs.type_at(0); - - let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?; - self.write_pointer(offset_ptr, dest)?; - } sym::arith_offset => { let ptr = self.read_pointer(&args[0])?; let offset_count = self.read_target_isize(&args[1])?; diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index c7d3f6c9f04..62b727674c5 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -192,6 +192,23 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { terminator.kind = TerminatorKind::Goto { target }; } } + sym::offset => { + let target = target.unwrap(); + let Ok([ptr, delta]) = <[_; 2]>::try_from(std::mem::take(args)) else { + span_bug!( + terminator.source_info.span, + "Wrong number of arguments for offset intrinsic", + ); + }; + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + *destination, + Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, delta))), + ))), + }); + terminator.kind = TerminatorKind::Goto { target }; + } sym::option_payload_ptr => { if let (Some(target), Some(arg)) = (*target, args[0].place()) { let ty::RawPtr(ty::TypeAndMut { ty: dest_ty, .. }) = diff --git a/tests/mir-opt/lower_intrinsics.ptr_offset.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.ptr_offset.LowerIntrinsics.diff new file mode 100644 index 00000000000..f342bf30d02 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.ptr_offset.LowerIntrinsics.diff @@ -0,0 +1,30 @@ +- // MIR for `ptr_offset` before LowerIntrinsics ++ // MIR for `ptr_offset` after LowerIntrinsics + + fn ptr_offset(_1: *const i32, _2: isize) -> *const i32 { + debug p => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:26: +0:27 + debug d => _2; // in scope 0 at $DIR/lower_intrinsics.rs:+0:41: +0:42 + let mut _0: *const i32; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:54: +0:64 + let mut _3: *const i32; // in scope 0 at $DIR/lower_intrinsics.rs:+1:30: +1:31 + let mut _4: isize; // in scope 0 at $DIR/lower_intrinsics.rs:+1:33: +1:34 + + bb0: { + StorageLive(_3); // scope 0 at $DIR/lower_intrinsics.rs:+1:30: +1:31 + _3 = _1; // scope 0 at $DIR/lower_intrinsics.rs:+1:30: +1:31 + StorageLive(_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:33: +1:34 + _4 = _2; // scope 0 at $DIR/lower_intrinsics.rs:+1:33: +1:34 +- _0 = offset::(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:140:5: 140:29 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, isize) -> *const i32 {offset::}, 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 + } + + bb1: { + StorageDead(_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:34: +1:35 + StorageDead(_3); // scope 0 at $DIR/lower_intrinsics.rs:+1:34: +1:35 + return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index 33fef930ad3..ad690f803c4 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs @@ -134,3 +134,8 @@ pub fn option_payload(o: &Option, p: &Option) { let _y = core::intrinsics::option_payload_ptr(p); } } + +// EMIT_MIR lower_intrinsics.ptr_offset.LowerIntrinsics.diff +pub unsafe fn ptr_offset(p: *const i32, d: isize) -> *const i32 { + core::intrinsics::offset(p, d) +}