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.
This commit is contained in:
Scott McMurray 2023-04-25 12:10:55 -07:00
parent a7aa20517c
commit 05a665f21a
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 // The only difference between offset and arith_offset is regarding UB. Because Cranelift
// doesn't have UB both are codegen'ed the same way // 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); intrinsic_args!(fx, args => (base, offset); intrinsic);
let offset = offset.load_scalar(fx); let offset = offset.load_scalar(fx);

View File

@ -135,13 +135,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
.unwrap(); .unwrap();
OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx) 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 => { sym::arith_offset => {
let ty = substs.type_at(0); let ty = substs.type_at(0);
let layout = bx.layout_of(ty); 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( fn binary_ptr_op(
_ecx: &InterpCx<'mir, 'tcx, Self>, ecx: &InterpCx<'mir, 'tcx, Self>,
_bin_op: mir::BinOp, bin_op: mir::BinOp,
_left: &ImmTy<'tcx>, left: &ImmTy<'tcx>,
_right: &ImmTy<'tcx>, right: &ImmTy<'tcx>,
) -> InterpResult<'tcx, (Scalar, bool, Ty<'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"); 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 => { sym::write_bytes => {
self.write_bytes_intrinsic(&args[0], &args[1], &args[2])?; 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 => { sym::arith_offset => {
let ptr = self.read_pointer(&args[0])?; let ptr = self.read_pointer(&args[0])?;
let offset_count = self.read_target_isize(&args[1])?; 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 }; 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 => { sym::option_payload_ptr => {
if let (Some(target), Some(arg)) = (*target, args[0].place()) { if let (Some(target), Some(arg)) = (*target, args[0].place()) {
let ty::RawPtr(ty::TypeAndMut { ty: dest_ty, .. }) = 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); 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)
}