Auto merge of #110822 - scottmcm:lower-offset-to-mir, r=compiler-errors

Lower `intrinsics::offset` to `mir::BinOp::Offset`

They're [semantically the same](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.Rvalue.html#variant.BinaryOp), so this means the backends don't need to handle the intrinsic and means fewer MIR basic blocks in pointer arithmetic code.
This commit is contained in:
bors 2023-04-26 15:52:33 +00:00
commit 9c044d77a3
7 changed files with 66 additions and 20 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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");
}

View File

@ -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])?;

View File

@ -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, .. }) =

View File

@ -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::<i32>(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::<i32>}, val: Value(<ZST>) }
+ _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
}
}

View File

@ -134,3 +134,8 @@ pub fn option_payload(o: &Option<usize>, p: &Option<String>) {
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)
}