2020-11-14 00:00:00 +00:00
|
|
|
//! Lowers intrinsic calls
|
|
|
|
|
|
|
|
use rustc_middle::mir::*;
|
2023-10-09 03:22:31 +00:00
|
|
|
use rustc_middle::ty::{self, TyCtxt};
|
2024-05-08 09:46:29 +00:00
|
|
|
use rustc_middle::{bug, span_bug};
|
2023-10-09 03:22:31 +00:00
|
|
|
use rustc_span::symbol::sym;
|
2020-11-14 00:00:00 +00:00
|
|
|
|
|
|
|
pub struct LowerIntrinsics;
|
|
|
|
|
|
|
|
impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
|
|
|
|
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
2022-07-04 00:00:00 +00:00
|
|
|
let local_decls = &body.local_decls;
|
|
|
|
for block in body.basic_blocks.as_mut() {
|
2020-11-14 00:00:00 +00:00
|
|
|
let terminator = block.terminator.as_mut().unwrap();
|
2022-04-16 13:27:54 +00:00
|
|
|
if let TerminatorKind::Call { func, args, destination, target, .. } =
|
|
|
|
&mut terminator.kind
|
2023-10-09 03:22:31 +00:00
|
|
|
&& let ty::FnDef(def_id, generic_args) = *func.ty(local_decls, tcx).kind()
|
2024-02-19 17:35:12 +00:00
|
|
|
&& let Some(intrinsic) = tcx.intrinsic(def_id)
|
2022-04-16 13:27:54 +00:00
|
|
|
{
|
2024-02-19 17:35:12 +00:00
|
|
|
match intrinsic.name {
|
2020-11-14 00:00:00 +00:00
|
|
|
sym::unreachable => {
|
|
|
|
terminator.kind = TerminatorKind::Unreachable;
|
|
|
|
}
|
2024-03-17 09:29:02 +00:00
|
|
|
sym::ub_checks => {
|
2024-02-07 15:26:00 +00:00
|
|
|
let target = target.unwrap();
|
|
|
|
block.statements.push(Statement {
|
|
|
|
source_info: terminator.source_info,
|
|
|
|
kind: StatementKind::Assign(Box::new((
|
|
|
|
*destination,
|
2024-03-17 09:29:02 +00:00
|
|
|
Rvalue::NullaryOp(NullOp::UbChecks, tcx.types.bool),
|
2024-02-07 15:26:00 +00:00
|
|
|
))),
|
|
|
|
});
|
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
|
|
|
}
|
2020-11-14 00:00:00 +00:00
|
|
|
sym::forget => {
|
2022-04-16 13:27:54 +00:00
|
|
|
if let Some(target) = *target {
|
2020-11-14 00:00:00 +00:00
|
|
|
block.statements.push(Statement {
|
|
|
|
source_info: terminator.source_info,
|
2021-08-05 03:36:38 +00:00
|
|
|
kind: StatementKind::Assign(Box::new((
|
2022-04-16 13:27:54 +00:00
|
|
|
*destination,
|
2023-09-20 18:51:14 +00:00
|
|
|
Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
|
2020-11-14 00:00:00 +00:00
|
|
|
span: terminator.source_info.span,
|
|
|
|
user_ty: None,
|
2023-09-20 18:51:14 +00:00
|
|
|
const_: Const::zero_sized(tcx.types.unit),
|
2021-08-05 03:36:38 +00:00
|
|
|
}))),
|
|
|
|
))),
|
2020-11-14 00:00:00 +00:00
|
|
|
});
|
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
|
|
|
}
|
|
|
|
}
|
2021-01-23 08:57:04 +00:00
|
|
|
sym::copy_nonoverlapping => {
|
2022-04-16 13:27:54 +00:00
|
|
|
let target = target.unwrap();
|
2021-01-23 08:57:04 +00:00
|
|
|
let mut args = args.drain(..);
|
|
|
|
block.statements.push(Statement {
|
|
|
|
source_info: terminator.source_info,
|
2022-07-12 10:05:00 +00:00
|
|
|
kind: StatementKind::Intrinsic(Box::new(
|
|
|
|
NonDivergingIntrinsic::CopyNonOverlapping(
|
|
|
|
rustc_middle::mir::CopyNonOverlapping {
|
2024-01-12 07:21:42 +00:00
|
|
|
src: args.next().unwrap().node,
|
|
|
|
dst: args.next().unwrap().node,
|
|
|
|
count: args.next().unwrap().node,
|
2022-07-12 10:05:00 +00:00
|
|
|
},
|
|
|
|
),
|
2021-08-05 03:36:38 +00:00
|
|
|
)),
|
2021-01-23 08:57:04 +00:00
|
|
|
});
|
|
|
|
assert_eq!(
|
|
|
|
args.next(),
|
|
|
|
None,
|
|
|
|
"Extra argument for copy_non_overlapping intrinsic"
|
|
|
|
);
|
|
|
|
drop(args);
|
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
|
|
|
}
|
2022-06-30 08:16:05 +00:00
|
|
|
sym::assume => {
|
|
|
|
let target = target.unwrap();
|
|
|
|
let mut args = args.drain(..);
|
|
|
|
block.statements.push(Statement {
|
|
|
|
source_info: terminator.source_info,
|
2022-07-12 10:05:00 +00:00
|
|
|
kind: StatementKind::Intrinsic(Box::new(
|
2024-01-12 07:21:42 +00:00
|
|
|
NonDivergingIntrinsic::Assume(args.next().unwrap().node),
|
2022-07-12 10:05:00 +00:00
|
|
|
)),
|
2022-06-30 08:16:05 +00:00
|
|
|
});
|
2022-07-12 10:05:00 +00:00
|
|
|
assert_eq!(
|
|
|
|
args.next(),
|
|
|
|
None,
|
|
|
|
"Extra argument for copy_non_overlapping intrinsic"
|
|
|
|
);
|
2022-06-30 08:16:05 +00:00
|
|
|
drop(args);
|
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
|
|
|
}
|
2023-06-01 06:58:20 +00:00
|
|
|
sym::wrapping_add
|
|
|
|
| sym::wrapping_sub
|
|
|
|
| sym::wrapping_mul
|
2023-03-06 04:19:41 +00:00
|
|
|
| sym::three_way_compare
|
2023-06-03 07:41:50 +00:00
|
|
|
| sym::unchecked_add
|
|
|
|
| sym::unchecked_sub
|
|
|
|
| sym::unchecked_mul
|
2023-06-01 06:58:20 +00:00
|
|
|
| sym::unchecked_div
|
2023-06-03 07:41:50 +00:00
|
|
|
| sym::unchecked_rem
|
|
|
|
| sym::unchecked_shl
|
|
|
|
| sym::unchecked_shr => {
|
2023-06-01 06:58:20 +00:00
|
|
|
let target = target.unwrap();
|
|
|
|
let lhs;
|
|
|
|
let rhs;
|
|
|
|
{
|
|
|
|
let mut args = args.drain(..);
|
|
|
|
lhs = args.next().unwrap();
|
|
|
|
rhs = args.next().unwrap();
|
2020-11-14 00:00:00 +00:00
|
|
|
}
|
2024-02-19 17:35:12 +00:00
|
|
|
let bin_op = match intrinsic.name {
|
2023-06-01 06:58:20 +00:00
|
|
|
sym::wrapping_add => BinOp::Add,
|
|
|
|
sym::wrapping_sub => BinOp::Sub,
|
|
|
|
sym::wrapping_mul => BinOp::Mul,
|
2023-03-06 04:19:41 +00:00
|
|
|
sym::three_way_compare => BinOp::Cmp,
|
2023-06-03 07:41:50 +00:00
|
|
|
sym::unchecked_add => BinOp::AddUnchecked,
|
|
|
|
sym::unchecked_sub => BinOp::SubUnchecked,
|
|
|
|
sym::unchecked_mul => BinOp::MulUnchecked,
|
2023-06-01 06:58:20 +00:00
|
|
|
sym::unchecked_div => BinOp::Div,
|
|
|
|
sym::unchecked_rem => BinOp::Rem,
|
2023-06-03 07:41:50 +00:00
|
|
|
sym::unchecked_shl => BinOp::ShlUnchecked,
|
|
|
|
sym::unchecked_shr => BinOp::ShrUnchecked,
|
2023-06-01 06:58:20 +00:00
|
|
|
_ => bug!("unexpected intrinsic"),
|
|
|
|
};
|
|
|
|
block.statements.push(Statement {
|
|
|
|
source_info: terminator.source_info,
|
|
|
|
kind: StatementKind::Assign(Box::new((
|
|
|
|
*destination,
|
2024-01-12 07:21:42 +00:00
|
|
|
Rvalue::BinaryOp(bin_op, Box::new((lhs.node, rhs.node))),
|
2023-06-01 06:58:20 +00:00
|
|
|
))),
|
|
|
|
});
|
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
2020-11-14 00:00:00 +00:00
|
|
|
}
|
|
|
|
sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
|
2023-02-18 21:45:10 +00:00
|
|
|
if let Some(target) = *target {
|
|
|
|
let lhs;
|
|
|
|
let rhs;
|
|
|
|
{
|
|
|
|
let mut args = args.drain(..);
|
|
|
|
lhs = args.next().unwrap();
|
|
|
|
rhs = args.next().unwrap();
|
|
|
|
}
|
2024-02-19 17:35:12 +00:00
|
|
|
let bin_op = match intrinsic.name {
|
2024-05-16 09:07:31 +00:00
|
|
|
sym::add_with_overflow => BinOp::AddWithOverflow,
|
|
|
|
sym::sub_with_overflow => BinOp::SubWithOverflow,
|
|
|
|
sym::mul_with_overflow => BinOp::MulWithOverflow,
|
2023-02-18 21:45:10 +00:00
|
|
|
_ => bug!("unexpected intrinsic"),
|
|
|
|
};
|
|
|
|
block.statements.push(Statement {
|
|
|
|
source_info: terminator.source_info,
|
|
|
|
kind: StatementKind::Assign(Box::new((
|
|
|
|
*destination,
|
2024-05-16 09:07:31 +00:00
|
|
|
Rvalue::BinaryOp(bin_op, Box::new((lhs.node, rhs.node))),
|
2023-02-18 21:45:10 +00:00
|
|
|
))),
|
|
|
|
});
|
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
|
|
|
}
|
2020-11-14 00:00:00 +00:00
|
|
|
}
|
2021-09-07 15:06:07 +00:00
|
|
|
sym::size_of | sym::min_align_of => {
|
2022-04-16 13:27:54 +00:00
|
|
|
if let Some(target) = *target {
|
2023-07-11 21:35:29 +00:00
|
|
|
let tp_ty = generic_args.type_at(0);
|
2024-02-19 17:35:12 +00:00
|
|
|
let null_op = match intrinsic.name {
|
2021-09-07 15:06:07 +00:00
|
|
|
sym::size_of => NullOp::SizeOf,
|
|
|
|
sym::min_align_of => NullOp::AlignOf,
|
|
|
|
_ => bug!("unexpected intrinsic"),
|
|
|
|
};
|
2020-11-14 00:00:00 +00:00
|
|
|
block.statements.push(Statement {
|
|
|
|
source_info: terminator.source_info,
|
2021-08-05 03:36:38 +00:00
|
|
|
kind: StatementKind::Assign(Box::new((
|
2022-04-16 13:27:54 +00:00
|
|
|
*destination,
|
2021-09-07 15:06:07 +00:00
|
|
|
Rvalue::NullaryOp(null_op, tp_ty),
|
2021-08-05 03:36:38 +00:00
|
|
|
))),
|
2020-11-14 00:00:00 +00:00
|
|
|
});
|
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
|
|
|
}
|
|
|
|
}
|
2023-03-11 23:32:54 +00:00
|
|
|
sym::read_via_copy => {
|
2023-03-15 05:24:28 +00:00
|
|
|
let [arg] = args.as_slice() else {
|
2023-03-11 23:32:54 +00:00
|
|
|
span_bug!(terminator.source_info.span, "Wrong number of arguments");
|
|
|
|
};
|
2024-01-12 07:21:42 +00:00
|
|
|
let derefed_place = if let Some(place) = arg.node.place()
|
2023-03-11 23:32:54 +00:00
|
|
|
&& let Some(local) = place.as_local()
|
|
|
|
{
|
|
|
|
tcx.mk_place_deref(local.into())
|
|
|
|
} else {
|
|
|
|
span_bug!(
|
|
|
|
terminator.source_info.span,
|
|
|
|
"Only passing a local is supported"
|
|
|
|
);
|
|
|
|
};
|
2023-09-04 13:32:07 +00:00
|
|
|
// Add new statement at the end of the block that does the read, and patch
|
|
|
|
// up the terminator.
|
|
|
|
block.statements.push(Statement {
|
|
|
|
source_info: terminator.source_info,
|
|
|
|
kind: StatementKind::Assign(Box::new((
|
|
|
|
*destination,
|
|
|
|
Rvalue::Use(Operand::Copy(derefed_place)),
|
|
|
|
))),
|
|
|
|
});
|
2023-03-15 05:24:28 +00:00
|
|
|
terminator.kind = match *target {
|
|
|
|
None => {
|
|
|
|
// No target means this read something uninhabited,
|
2023-09-04 13:32:07 +00:00
|
|
|
// so it must be unreachable.
|
2023-03-15 05:24:28 +00:00
|
|
|
TerminatorKind::Unreachable
|
|
|
|
}
|
2023-09-04 13:32:07 +00:00
|
|
|
Some(target) => TerminatorKind::Goto { target },
|
2023-03-11 23:32:54 +00:00
|
|
|
}
|
|
|
|
}
|
2023-04-30 06:32:40 +00:00
|
|
|
sym::write_via_move => {
|
|
|
|
let target = target.unwrap();
|
|
|
|
let Ok([ptr, val]) = <[_; 2]>::try_from(std::mem::take(args)) else {
|
|
|
|
span_bug!(
|
|
|
|
terminator.source_info.span,
|
|
|
|
"Wrong number of arguments for write_via_move intrinsic",
|
|
|
|
);
|
|
|
|
};
|
2024-01-12 07:21:42 +00:00
|
|
|
let derefed_place = if let Some(place) = ptr.node.place()
|
2023-04-30 06:32:40 +00:00
|
|
|
&& let Some(local) = place.as_local()
|
|
|
|
{
|
|
|
|
tcx.mk_place_deref(local.into())
|
|
|
|
} else {
|
|
|
|
span_bug!(
|
|
|
|
terminator.source_info.span,
|
|
|
|
"Only passing a local is supported"
|
|
|
|
);
|
|
|
|
};
|
|
|
|
block.statements.push(Statement {
|
|
|
|
source_info: terminator.source_info,
|
|
|
|
kind: StatementKind::Assign(Box::new((
|
|
|
|
derefed_place,
|
2024-01-12 07:21:42 +00:00
|
|
|
Rvalue::Use(val.node),
|
2023-04-30 06:32:40 +00:00
|
|
|
))),
|
|
|
|
});
|
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
|
|
|
}
|
2020-12-11 00:00:00 +00:00
|
|
|
sym::discriminant_value => {
|
2024-01-12 07:21:42 +00:00
|
|
|
if let (Some(target), Some(arg)) = (*target, args[0].node.place()) {
|
2020-12-11 00:00:00 +00:00
|
|
|
let arg = tcx.mk_place_deref(arg);
|
|
|
|
block.statements.push(Statement {
|
|
|
|
source_info: terminator.source_info,
|
2021-08-05 03:36:38 +00:00
|
|
|
kind: StatementKind::Assign(Box::new((
|
2022-04-16 13:27:54 +00:00
|
|
|
*destination,
|
2020-12-11 00:00:00 +00:00
|
|
|
Rvalue::Discriminant(arg),
|
2021-08-05 03:36:38 +00:00
|
|
|
))),
|
2020-12-11 00:00:00 +00:00
|
|
|
});
|
2023-03-15 15:29:52 +00:00
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
|
|
|
}
|
|
|
|
}
|
2023-04-25 19:10:55 +00:00
|
|
|
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,
|
2024-01-12 07:21:42 +00:00
|
|
|
Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr.node, delta.node))),
|
2023-04-25 19:10:55 +00:00
|
|
|
))),
|
|
|
|
});
|
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
|
|
|
}
|
2023-04-23 00:14:19 +00:00
|
|
|
sym::transmute | sym::transmute_unchecked => {
|
2023-02-25 02:32:52 +00:00
|
|
|
let dst_ty = destination.ty(local_decls, tcx).ty;
|
|
|
|
let Ok([arg]) = <[_; 1]>::try_from(std::mem::take(args)) else {
|
|
|
|
span_bug!(
|
|
|
|
terminator.source_info.span,
|
|
|
|
"Wrong number of arguments for transmute intrinsic",
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Always emit the cast, even if we transmute to an uninhabited type,
|
|
|
|
// because that lets CTFE and codegen generate better error messages
|
|
|
|
// when such a transmute actually ends up reachable.
|
|
|
|
block.statements.push(Statement {
|
|
|
|
source_info: terminator.source_info,
|
|
|
|
kind: StatementKind::Assign(Box::new((
|
|
|
|
*destination,
|
2024-01-12 07:21:42 +00:00
|
|
|
Rvalue::Cast(CastKind::Transmute, arg.node, dst_ty),
|
2023-02-25 02:32:52 +00:00
|
|
|
))),
|
|
|
|
});
|
|
|
|
|
|
|
|
if let Some(target) = *target {
|
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
|
|
|
} else {
|
|
|
|
terminator.kind = TerminatorKind::Unreachable;
|
|
|
|
}
|
|
|
|
}
|
2024-04-11 22:33:37 +00:00
|
|
|
sym::aggregate_raw_ptr => {
|
|
|
|
let Ok([data, meta]) = <[_; 2]>::try_from(std::mem::take(args)) else {
|
|
|
|
span_bug!(
|
|
|
|
terminator.source_info.span,
|
|
|
|
"Wrong number of arguments for aggregate_raw_ptr intrinsic",
|
|
|
|
);
|
|
|
|
};
|
|
|
|
let target = target.unwrap();
|
|
|
|
let pointer_ty = generic_args.type_at(0);
|
|
|
|
let kind = if let ty::RawPtr(pointee_ty, mutability) = pointer_ty.kind() {
|
|
|
|
AggregateKind::RawPtr(*pointee_ty, *mutability)
|
|
|
|
} else {
|
|
|
|
span_bug!(
|
|
|
|
terminator.source_info.span,
|
|
|
|
"Return type of aggregate_raw_ptr intrinsic must be a raw pointer",
|
|
|
|
);
|
|
|
|
};
|
|
|
|
let fields = [data.node, meta.node];
|
|
|
|
block.statements.push(Statement {
|
|
|
|
source_info: terminator.source_info,
|
|
|
|
kind: StatementKind::Assign(Box::new((
|
|
|
|
*destination,
|
|
|
|
Rvalue::Aggregate(Box::new(kind), fields.into()),
|
|
|
|
))),
|
|
|
|
});
|
|
|
|
|
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
|
|
|
}
|
2024-04-21 23:11:01 +00:00
|
|
|
sym::ptr_metadata => {
|
|
|
|
let Ok([ptr]) = <[_; 1]>::try_from(std::mem::take(args)) else {
|
|
|
|
span_bug!(
|
|
|
|
terminator.source_info.span,
|
|
|
|
"Wrong number of arguments for ptr_metadata intrinsic",
|
|
|
|
);
|
|
|
|
};
|
|
|
|
let target = target.unwrap();
|
|
|
|
block.statements.push(Statement {
|
|
|
|
source_info: terminator.source_info,
|
|
|
|
kind: StatementKind::Assign(Box::new((
|
|
|
|
*destination,
|
|
|
|
Rvalue::UnaryOp(UnOp::PtrMetadata, ptr.node),
|
|
|
|
))),
|
|
|
|
});
|
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
|
|
|
}
|
2020-11-14 00:00:00 +00:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|