]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir/src/transform/lower_intrinsics.rs
Rollup merge of #82789 - csmoe:issue-82772, r=estebank
[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::copy_nonoverlapping => {
44                         let target = destination.unwrap().1;
45                         let mut args = args.drain(..);
46                         block.statements.push(Statement {
47                             source_info: terminator.source_info,
48                             kind: StatementKind::CopyNonOverlapping(
49                                 box rustc_middle::mir::CopyNonOverlapping {
50                                     src: args.next().unwrap(),
51                                     dst: args.next().unwrap(),
52                                     count: args.next().unwrap(),
53                                 },
54                             ),
55                         });
56                         assert_eq!(
57                             args.next(),
58                             None,
59                             "Extra argument for copy_non_overlapping intrinsic"
60                         );
61                         drop(args);
62                         terminator.kind = TerminatorKind::Goto { target };
63                     }
64                     sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => {
65                         if let Some((destination, target)) = *destination {
66                             let lhs;
67                             let rhs;
68                             {
69                                 let mut args = args.drain(..);
70                                 lhs = args.next().unwrap();
71                                 rhs = args.next().unwrap();
72                             }
73                             let bin_op = match intrinsic_name {
74                                 sym::wrapping_add => BinOp::Add,
75                                 sym::wrapping_sub => BinOp::Sub,
76                                 sym::wrapping_mul => BinOp::Mul,
77                                 _ => bug!("unexpected intrinsic"),
78                             };
79                             block.statements.push(Statement {
80                                 source_info: terminator.source_info,
81                                 kind: StatementKind::Assign(box (
82                                     destination,
83                                     Rvalue::BinaryOp(bin_op, box (lhs, rhs)),
84                                 )),
85                             });
86                             terminator.kind = TerminatorKind::Goto { target };
87                         }
88                     }
89                     sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
90                         // The checked binary operations are not suitable target for lowering here,
91                         // since their semantics depend on the value of overflow-checks flag used
92                         // during codegen. Issue #35310.
93                     }
94                     sym::size_of => {
95                         if let Some((destination, target)) = *destination {
96                             let tp_ty = substs.type_at(0);
97                             block.statements.push(Statement {
98                                 source_info: terminator.source_info,
99                                 kind: StatementKind::Assign(box (
100                                     destination,
101                                     Rvalue::NullaryOp(NullOp::SizeOf, tp_ty),
102                                 )),
103                             });
104                             terminator.kind = TerminatorKind::Goto { target };
105                         }
106                     }
107                     sym::discriminant_value => {
108                         if let (Some((destination, target)), Some(arg)) =
109                             (*destination, args[0].place())
110                         {
111                             let arg = tcx.mk_place_deref(arg);
112                             block.statements.push(Statement {
113                                 source_info: terminator.source_info,
114                                 kind: StatementKind::Assign(box (
115                                     destination,
116                                     Rvalue::Discriminant(arg),
117                                 )),
118                             });
119                             terminator.kind = TerminatorKind::Goto { target };
120                         }
121                     }
122                     _ => {}
123                 }
124             }
125         }
126     }
127 }
128
129 fn resolve_rust_intrinsic(
130     tcx: TyCtxt<'tcx>,
131     func_ty: Ty<'tcx>,
132 ) -> Option<(Symbol, SubstsRef<'tcx>)> {
133     if let ty::FnDef(def_id, substs) = *func_ty.kind() {
134         let fn_sig = func_ty.fn_sig(tcx);
135         if fn_sig.abi() == Abi::RustIntrinsic {
136             return Some((tcx.item_name(def_id), substs));
137         }
138     }
139     None
140 }