]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir/src/transform/lower_intrinsics.rs
Shrink the size of Rvalue by 16 bytes
[rust.git] / compiler / rustc_mir / src / transform / lower_intrinsics.rs
1 //! Lowers intrinsic calls
2
3 use crate::transform::MirPass;
4 use rustc_middle::mir::*;
5 use rustc_middle::ty::subst::SubstsRef;
6 use rustc_middle::ty::{self, Ty, TyCtxt};
7 use rustc_span::symbol::{sym, Symbol};
8 use rustc_target::spec::abi::Abi;
9
10 pub struct LowerIntrinsics;
11
12 impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
13     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
14         let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
15         for block in basic_blocks {
16             let terminator = block.terminator.as_mut().unwrap();
17             if let TerminatorKind::Call { func, args, destination, .. } = &mut terminator.kind {
18                 let func_ty = func.ty(local_decls, tcx);
19                 let (intrinsic_name, substs) = match resolve_rust_intrinsic(tcx, func_ty) {
20                     None => continue,
21                     Some(it) => it,
22                 };
23                 match intrinsic_name {
24                     sym::unreachable => {
25                         terminator.kind = TerminatorKind::Unreachable;
26                     }
27                     sym::forget => {
28                         if let Some((destination, target)) = *destination {
29                             block.statements.push(Statement {
30                                 source_info: terminator.source_info,
31                                 kind: StatementKind::Assign(box (
32                                     destination,
33                                     Rvalue::Use(Operand::Constant(box Constant {
34                                         span: terminator.source_info.span,
35                                         user_ty: None,
36                                         literal: ty::Const::zero_sized(tcx, tcx.types.unit),
37                                     })),
38                                 )),
39                             });
40                             terminator.kind = TerminatorKind::Goto { target };
41                         }
42                     }
43                     sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => {
44                         if let Some((destination, target)) = *destination {
45                             let lhs;
46                             let rhs;
47                             {
48                                 let mut args = args.drain(..);
49                                 lhs = args.next().unwrap();
50                                 rhs = args.next().unwrap();
51                             }
52                             let bin_op = match intrinsic_name {
53                                 sym::wrapping_add => BinOp::Add,
54                                 sym::wrapping_sub => BinOp::Sub,
55                                 sym::wrapping_mul => BinOp::Mul,
56                                 _ => bug!("unexpected intrinsic"),
57                             };
58                             block.statements.push(Statement {
59                                 source_info: terminator.source_info,
60                                 kind: StatementKind::Assign(box (
61                                     destination,
62                                     Rvalue::BinaryOp(bin_op, box (lhs, rhs)),
63                                 )),
64                             });
65                             terminator.kind = TerminatorKind::Goto { target };
66                         }
67                     }
68                     sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
69                         // The checked binary operations are not suitable target for lowering here,
70                         // since their semantics depend on the value of overflow-checks flag used
71                         // during codegen. Issue #35310.
72                     }
73                     sym::size_of => {
74                         if let Some((destination, target)) = *destination {
75                             let tp_ty = substs.type_at(0);
76                             block.statements.push(Statement {
77                                 source_info: terminator.source_info,
78                                 kind: StatementKind::Assign(box (
79                                     destination,
80                                     Rvalue::NullaryOp(NullOp::SizeOf, tp_ty),
81                                 )),
82                             });
83                             terminator.kind = TerminatorKind::Goto { target };
84                         }
85                     }
86                     sym::discriminant_value => {
87                         if let (Some((destination, target)), Some(arg)) =
88                             (*destination, args[0].place())
89                         {
90                             let arg = tcx.mk_place_deref(arg);
91                             block.statements.push(Statement {
92                                 source_info: terminator.source_info,
93                                 kind: StatementKind::Assign(box (
94                                     destination,
95                                     Rvalue::Discriminant(arg),
96                                 )),
97                             });
98                             terminator.kind = TerminatorKind::Goto { target };
99                         }
100                     }
101                     _ => {}
102                 }
103             }
104         }
105     }
106 }
107
108 fn resolve_rust_intrinsic(
109     tcx: TyCtxt<'tcx>,
110     func_ty: Ty<'tcx>,
111 ) -> Option<(Symbol, SubstsRef<'tcx>)> {
112     if let ty::FnDef(def_id, substs) = *func_ty.kind() {
113         let fn_sig = func_ty.fn_sig(tcx);
114         if fn_sig.abi() == Abi::RustIntrinsic {
115             return Some((tcx.item_name(def_id), substs));
116         }
117     }
118     None
119 }