diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_mir/src/transform/lower_intrinsics.rs | 108 | ||||
| -rw-r--r-- | compiler/rustc_mir/src/transform/mod.rs | 2 |
2 files changed, 110 insertions, 0 deletions
diff --git a/compiler/rustc_mir/src/transform/lower_intrinsics.rs b/compiler/rustc_mir/src/transform/lower_intrinsics.rs new file mode 100644 index 00000000000..da937094c41 --- /dev/null +++ b/compiler/rustc_mir/src/transform/lower_intrinsics.rs @@ -0,0 +1,108 @@ +//! Lowers intrinsic calls + +use crate::transform::MirPass; +use rustc_middle::mir::*; +use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::symbol::{sym, Symbol}; +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>) { + for block in body.basic_blocks_mut() { + let terminator = block.terminator.as_mut().unwrap(); + if let TerminatorKind::Call { + func: Operand::Constant(box Constant { literal: ty::Const { ty: func_ty, .. }, .. }), + args, + destination, + .. + } = &mut terminator.kind + { + 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, + kind: StatementKind::Assign(box ( + destination, + Rvalue::Use(Operand::Constant(box Constant { + span: terminator.source_info.span, + user_ty: None, + literal: ty::Const::zero_sized(tcx, tcx.types.unit), + })), + )), + }); + terminator.kind = TerminatorKind::Goto { target }; + } + } + 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, + kind: StatementKind::Assign(box ( + destination, + Rvalue::BinaryOp(bin_op, lhs, rhs), + )), + }); + 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. + } + sym::size_of => { + if let Some((destination, target)) = *destination { + let tp_ty = substs.type_at(0); + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(box ( + destination, + Rvalue::NullaryOp(NullOp::SizeOf, tp_ty), + )), + }); + terminator.kind = TerminatorKind::Goto { target }; + } + } + _ => {} + } + } + } + } +} + +fn resolve_rust_intrinsic( + 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); + if fn_sig.abi() == Abi::RustIntrinsic { + return Some((tcx.item_name(def_id), substs)); + } + } + None +} diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index e3fea2d2701..2f81db8af2f 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -32,6 +32,7 @@ pub mod function_item_references; pub mod generator; pub mod inline; pub mod instcombine; +pub mod lower_intrinsics; pub mod match_branches; pub mod multiple_return_terminators; pub mod no_landing_pads; @@ -390,6 +391,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // The main optimizations that we do on MIR. let optimizations: &[&dyn MirPass<'tcx>] = &[ + &lower_intrinsics::LowerIntrinsics, &remove_unneeded_drops::RemoveUnneededDrops, &match_branches::MatchBranchSimplification, // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) |
