2020-11-13 18:00:00 -06:00
|
|
|
//! Lowers intrinsic calls
|
|
|
|
|
2020-12-31 18:53:25 -06:00
|
|
|
use crate::MirPass;
|
2020-11-13 18:00:00 -06:00
|
|
|
use rustc_middle::mir::*;
|
|
|
|
use rustc_middle::ty::subst::SubstsRef;
|
|
|
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
|
|
|
use rustc_span::symbol::{sym, Symbol};
|
2021-05-11 03:17:25 -05:00
|
|
|
use rustc_span::Span;
|
2020-11-13 18:00:00 -06:00
|
|
|
use rustc_target::spec::abi::Abi;
|
|
|
|
|
|
|
|
pub struct LowerIntrinsics;
|
|
|
|
|
|
|
|
impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
|
|
|
|
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
2020-11-15 18:00:00 -06:00
|
|
|
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
|
|
|
|
for block in basic_blocks {
|
2020-11-13 18:00:00 -06:00
|
|
|
let terminator = block.terminator.as_mut().unwrap();
|
2020-11-15 18:00:00 -06:00
|
|
|
if let TerminatorKind::Call { func, args, destination, .. } = &mut terminator.kind {
|
|
|
|
let func_ty = func.ty(local_decls, tcx);
|
2020-11-13 18:00:00 -06:00
|
|
|
let (intrinsic_name, substs) = match resolve_rust_intrinsic(tcx, func_ty) {
|
|
|
|
None => continue,
|
|
|
|
Some(it) => it,
|
|
|
|
};
|
|
|
|
match intrinsic_name {
|
|
|
|
sym::unreachable => {
|
|
|
|
terminator.kind = TerminatorKind::Unreachable;
|
|
|
|
}
|
|
|
|
sym::forget => {
|
|
|
|
if let Some((destination, target)) = *destination {
|
|
|
|
block.statements.push(Statement {
|
|
|
|
source_info: terminator.source_info,
|
2021-08-04 22:36:38 -05:00
|
|
|
kind: StatementKind::Assign(Box::new((
|
2020-11-13 18:00:00 -06:00
|
|
|
destination,
|
2021-08-04 22:36:38 -05:00
|
|
|
Rvalue::Use(Operand::Constant(Box::new(Constant {
|
2020-11-13 18:00:00 -06:00
|
|
|
span: terminator.source_info.span,
|
|
|
|
user_ty: None,
|
2021-03-08 10:18:03 -06:00
|
|
|
literal: ty::Const::zero_sized(tcx, tcx.types.unit).into(),
|
2021-08-04 22:36:38 -05:00
|
|
|
}))),
|
|
|
|
))),
|
2020-11-13 18:00:00 -06:00
|
|
|
});
|
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
|
|
|
}
|
|
|
|
}
|
2021-01-23 02:57:04 -06:00
|
|
|
sym::copy_nonoverlapping => {
|
|
|
|
let target = destination.unwrap().1;
|
|
|
|
let mut args = args.drain(..);
|
|
|
|
block.statements.push(Statement {
|
|
|
|
source_info: terminator.source_info,
|
2021-08-04 22:36:38 -05:00
|
|
|
kind: StatementKind::CopyNonOverlapping(Box::new(
|
|
|
|
rustc_middle::mir::CopyNonOverlapping {
|
2021-01-23 02:57:04 -06:00
|
|
|
src: args.next().unwrap(),
|
|
|
|
dst: args.next().unwrap(),
|
|
|
|
count: args.next().unwrap(),
|
|
|
|
},
|
2021-08-04 22:36:38 -05:00
|
|
|
)),
|
2021-01-23 02:57:04 -06:00
|
|
|
});
|
|
|
|
assert_eq!(
|
|
|
|
args.next(),
|
|
|
|
None,
|
|
|
|
"Extra argument for copy_non_overlapping intrinsic"
|
|
|
|
);
|
|
|
|
drop(args);
|
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
|
|
|
}
|
2020-11-13 18:00:00 -06:00
|
|
|
sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => {
|
|
|
|
if let Some((destination, target)) = *destination {
|
|
|
|
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,
|
2021-08-04 22:36:38 -05:00
|
|
|
kind: StatementKind::Assign(Box::new((
|
2020-11-13 18:00:00 -06:00
|
|
|
destination,
|
2021-08-04 22:36:38 -05:00
|
|
|
Rvalue::BinaryOp(bin_op, Box::new((lhs, rhs))),
|
|
|
|
))),
|
2020-11-13 18:00:00 -06:00
|
|
|
});
|
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
|
|
|
|
// The checked binary operations are not suitable target for lowering here,
|
|
|
|
// since their semantics depend on the value of overflow-checks flag used
|
|
|
|
// during codegen. Issue #35310.
|
|
|
|
}
|
2021-09-07 10:06:07 -05:00
|
|
|
sym::size_of | sym::min_align_of => {
|
2020-11-13 18:00:00 -06:00
|
|
|
if let Some((destination, target)) = *destination {
|
|
|
|
let tp_ty = substs.type_at(0);
|
2021-09-07 10:06:07 -05:00
|
|
|
let null_op = match intrinsic_name {
|
|
|
|
sym::size_of => NullOp::SizeOf,
|
|
|
|
sym::min_align_of => NullOp::AlignOf,
|
|
|
|
_ => bug!("unexpected intrinsic"),
|
|
|
|
};
|
2020-11-13 18:00:00 -06:00
|
|
|
block.statements.push(Statement {
|
|
|
|
source_info: terminator.source_info,
|
2021-08-04 22:36:38 -05:00
|
|
|
kind: StatementKind::Assign(Box::new((
|
2020-11-13 18:00:00 -06:00
|
|
|
destination,
|
2021-09-07 10:06:07 -05:00
|
|
|
Rvalue::NullaryOp(null_op, tp_ty),
|
2021-08-04 22:36:38 -05:00
|
|
|
))),
|
2020-11-13 18:00:00 -06:00
|
|
|
});
|
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
|
|
|
}
|
|
|
|
}
|
2020-12-10 18:00:00 -06:00
|
|
|
sym::discriminant_value => {
|
|
|
|
if let (Some((destination, target)), Some(arg)) =
|
|
|
|
(*destination, args[0].place())
|
|
|
|
{
|
|
|
|
let arg = tcx.mk_place_deref(arg);
|
|
|
|
block.statements.push(Statement {
|
|
|
|
source_info: terminator.source_info,
|
2021-08-04 22:36:38 -05:00
|
|
|
kind: StatementKind::Assign(Box::new((
|
2020-12-10 18:00:00 -06:00
|
|
|
destination,
|
|
|
|
Rvalue::Discriminant(arg),
|
2021-08-04 22:36:38 -05:00
|
|
|
))),
|
2020-12-10 18:00:00 -06:00
|
|
|
});
|
|
|
|
terminator.kind = TerminatorKind::Goto { target };
|
|
|
|
}
|
|
|
|
}
|
2021-05-11 03:17:25 -05:00
|
|
|
_ if intrinsic_name.as_str().starts_with("simd_shuffle") => {
|
|
|
|
validate_simd_shuffle(tcx, args, terminator.source_info.span);
|
|
|
|
}
|
2020-11-13 18:00:00 -06:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-06 02:48:37 -06:00
|
|
|
fn resolve_rust_intrinsic<'tcx>(
|
2020-11-13 18:00:00 -06:00
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
func_ty: Ty<'tcx>,
|
|
|
|
) -> Option<(Symbol, SubstsRef<'tcx>)> {
|
|
|
|
if let ty::FnDef(def_id, substs) = *func_ty.kind() {
|
|
|
|
let fn_sig = func_ty.fn_sig(tcx);
|
2021-05-11 03:17:25 -05:00
|
|
|
if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = fn_sig.abi() {
|
2020-11-13 18:00:00 -06:00
|
|
|
return Some((tcx.item_name(def_id), substs));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
2021-05-11 03:17:25 -05:00
|
|
|
|
2021-12-06 02:48:37 -06:00
|
|
|
fn validate_simd_shuffle<'tcx>(tcx: TyCtxt<'tcx>, args: &[Operand<'tcx>], span: Span) {
|
2021-05-11 03:17:25 -05:00
|
|
|
match &args[2] {
|
|
|
|
Operand::Constant(_) => {} // all good
|
|
|
|
_ => {
|
2021-07-21 15:43:19 -05:00
|
|
|
let msg = "last argument of `simd_shuffle` is required to be a `const` item";
|
|
|
|
tcx.sess.span_err(span, msg);
|
2021-05-11 03:17:25 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|