]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
Auto merge of #107843 - bjorn3:sync_cg_clif-2023-02-09, r=bjorn3
[rust.git] / compiler / rustc_mir_build / src / build / custom / parse / instruction.rs
1 use rustc_middle::mir::interpret::{ConstValue, Scalar};
2 use rustc_middle::mir::tcx::PlaceTy;
3 use rustc_middle::{mir::*, thir::*, ty};
4 use rustc_span::Span;
5 use rustc_target::abi::VariantIdx;
6
7 use crate::build::custom::ParseError;
8 use crate::build::expr::as_constant::as_constant_inner;
9
10 use super::{parse_by_kind, PResult, ParseCtxt};
11
12 impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
13     pub fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
14         parse_by_kind!(self, expr_id, _, "statement",
15             @call("mir_storage_live", args) => {
16                 Ok(StatementKind::StorageLive(self.parse_local(args[0])?))
17             },
18             @call("mir_storage_dead", args) => {
19                 Ok(StatementKind::StorageDead(self.parse_local(args[0])?))
20             },
21             @call("mir_deinit", args) => {
22                 Ok(StatementKind::Deinit(Box::new(self.parse_place(args[0])?)))
23             },
24             @call("mir_retag", args) => {
25                 Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?)))
26             },
27             @call("mir_set_discriminant", args) => {
28                 let place = self.parse_place(args[0])?;
29                 let var = self.parse_integer_literal(args[1])? as u32;
30                 Ok(StatementKind::SetDiscriminant {
31                     place: Box::new(place),
32                     variant_index: VariantIdx::from_u32(var),
33                 })
34             },
35             ExprKind::Assign { lhs, rhs } => {
36                 let lhs = self.parse_place(*lhs)?;
37                 let rhs = self.parse_rvalue(*rhs)?;
38                 Ok(StatementKind::Assign(Box::new((lhs, rhs))))
39             },
40         )
41     }
42
43     pub fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> {
44         parse_by_kind!(self, expr_id, expr, "terminator",
45             @call("mir_return", _args) => {
46                 Ok(TerminatorKind::Return)
47             },
48             @call("mir_goto", args) => {
49                 Ok(TerminatorKind::Goto { target: self.parse_block(args[0])? } )
50             },
51             @call("mir_unreachable", _args) => {
52                 Ok(TerminatorKind::Unreachable)
53             },
54             @call("mir_drop", args) => {
55                 Ok(TerminatorKind::Drop {
56                     place: self.parse_place(args[0])?,
57                     target: self.parse_block(args[1])?,
58                     unwind: None,
59                 })
60             },
61             @call("mir_drop_and_replace", args) => {
62                 Ok(TerminatorKind::DropAndReplace {
63                     place: self.parse_place(args[0])?,
64                     value: self.parse_operand(args[1])?,
65                     target: self.parse_block(args[2])?,
66                     unwind: None,
67                 })
68             },
69             @call("mir_call", args) => {
70                 let destination = self.parse_place(args[0])?;
71                 let target = self.parse_block(args[1])?;
72                 self.parse_call(args[2], destination, target)
73             },
74             ExprKind::Match { scrutinee, arms } => {
75                 let discr = self.parse_operand(*scrutinee)?;
76                 self.parse_match(arms, expr.span).map(|t| TerminatorKind::SwitchInt { discr, targets: t })
77             },
78         )
79     }
80
81     fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> {
82         let Some((otherwise, rest)) = arms.split_last() else {
83             return Err(ParseError {
84                 span,
85                 item_description: "no arms".to_string(),
86                 expected: "at least one arm".to_string(),
87             })
88         };
89
90         let otherwise = &self.thir[*otherwise];
91         let PatKind::Wild = otherwise.pattern.kind else {
92             return Err(ParseError {
93                 span: otherwise.span,
94                 item_description: format!("{:?}", otherwise.pattern.kind),
95                 expected: "wildcard pattern".to_string(),
96             })
97         };
98         let otherwise = self.parse_block(otherwise.body)?;
99
100         let mut values = Vec::new();
101         let mut targets = Vec::new();
102         for arm in rest {
103             let arm = &self.thir[*arm];
104             let PatKind::Constant { value } = arm.pattern.kind else {
105                 return Err(ParseError {
106                     span: arm.pattern.span,
107                     item_description: format!("{:?}", arm.pattern.kind),
108                     expected: "constant pattern".to_string(),
109                 })
110             };
111             values.push(value.eval_bits(self.tcx, self.param_env, arm.pattern.ty));
112             targets.push(self.parse_block(arm.body)?);
113         }
114
115         Ok(SwitchTargets::new(values.into_iter().zip(targets), otherwise))
116     }
117
118     fn parse_call(
119         &self,
120         expr_id: ExprId,
121         destination: Place<'tcx>,
122         target: BasicBlock,
123     ) -> PResult<TerminatorKind<'tcx>> {
124         parse_by_kind!(self, expr_id, _, "function call",
125             ExprKind::Call { fun, args, from_hir_call, fn_span, .. } => {
126                 let fun = self.parse_operand(*fun)?;
127                 let args = args
128                     .iter()
129                     .map(|arg| self.parse_operand(*arg))
130                     .collect::<PResult<Vec<_>>>()?;
131                 Ok(TerminatorKind::Call {
132                     func: fun,
133                     args,
134                     destination,
135                     target: Some(target),
136                     cleanup: None,
137                     from_hir_call: *from_hir_call,
138                     fn_span: *fn_span,
139                 })
140             },
141         )
142     }
143
144     fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
145         parse_by_kind!(self, expr_id, _, "rvalue",
146             @call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
147             @call("mir_checked", args) => {
148                 parse_by_kind!(self, args[0], _, "binary op",
149                     ExprKind::Binary { op, lhs, rhs } => Ok(Rvalue::CheckedBinaryOp(
150                         *op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?))
151                     )),
152                 )
153             },
154             @call("mir_len", args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
155             ExprKind::Borrow { borrow_kind, arg } => Ok(
156                 Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
157             ),
158             ExprKind::AddressOf { mutability, arg } => Ok(
159                 Rvalue::AddressOf(*mutability, self.parse_place(*arg)?)
160             ),
161             ExprKind::Binary { op, lhs, rhs } =>  Ok(
162                 Rvalue::BinaryOp(*op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?)))
163             ),
164             ExprKind::Unary { op, arg } => Ok(
165                 Rvalue::UnaryOp(*op, self.parse_operand(*arg)?)
166             ),
167             ExprKind::Repeat { value, count } => Ok(
168                 Rvalue::Repeat(self.parse_operand(*value)?, *count)
169             ),
170             _ => self.parse_operand(expr_id).map(Rvalue::Use),
171         )
172     }
173
174     fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
175         parse_by_kind!(self, expr_id, expr, "operand",
176             @call("mir_move", args) => self.parse_place(args[0]).map(Operand::Move),
177             @call("mir_static", args) => self.parse_static(args[0]),
178             @call("mir_static_mut", args) => self.parse_static(args[0]),
179             ExprKind::Literal { .. }
180             | ExprKind::NamedConst { .. }
181             | ExprKind::NonHirLiteral { .. }
182             | ExprKind::ZstLiteral { .. }
183             | ExprKind::ConstParam { .. }
184             | ExprKind::ConstBlock { .. } => {
185                 Ok(Operand::Constant(Box::new(
186                     as_constant_inner(expr, |_| None, self.tcx)
187                 )))
188             },
189             _ => self.parse_place(expr_id).map(Operand::Copy),
190         )
191     }
192
193     fn parse_place(&self, expr_id: ExprId) -> PResult<Place<'tcx>> {
194         self.parse_place_inner(expr_id).map(|(x, _)| x)
195     }
196
197     fn parse_place_inner(&self, expr_id: ExprId) -> PResult<(Place<'tcx>, PlaceTy<'tcx>)> {
198         let (parent, proj) = parse_by_kind!(self, expr_id, expr, "place",
199             @call("mir_field", args) => {
200                 let (parent, ty) = self.parse_place_inner(args[0])?;
201                 let field = Field::from_u32(self.parse_integer_literal(args[1])? as u32);
202                 let field_ty = ty.field_ty(self.tcx, field);
203                 let proj = PlaceElem::Field(field, field_ty);
204                 let place = parent.project_deeper(&[proj], self.tcx);
205                 return Ok((place, PlaceTy::from_ty(field_ty)));
206             },
207             @call("mir_variant", args) => {
208                 (args[0], PlaceElem::Downcast(
209                     None,
210                     VariantIdx::from_u32(self.parse_integer_literal(args[1])? as u32)
211                 ))
212             },
213             ExprKind::Deref { arg } => {
214                 parse_by_kind!(self, *arg, _, "does not matter",
215                     @call("mir_make_place", args) => return self.parse_place_inner(args[0]),
216                     _ => (*arg, PlaceElem::Deref),
217                 )
218             },
219             ExprKind::Index { lhs, index } => (*lhs, PlaceElem::Index(self.parse_local(*index)?)),
220             ExprKind::Field { lhs, name: field, .. } => (*lhs, PlaceElem::Field(*field, expr.ty)),
221             _ => {
222                 let place = self.parse_local(expr_id).map(Place::from)?;
223                 return Ok((place, PlaceTy::from_ty(expr.ty)))
224             },
225         );
226         let (parent, ty) = self.parse_place_inner(parent)?;
227         let place = parent.project_deeper(&[proj], self.tcx);
228         let ty = ty.projection_ty(self.tcx, proj);
229         Ok((place, ty))
230     }
231
232     fn parse_local(&self, expr_id: ExprId) -> PResult<Local> {
233         parse_by_kind!(self, expr_id, _, "local",
234             ExprKind::VarRef { id } => Ok(self.local_map[id]),
235         )
236     }
237
238     fn parse_block(&self, expr_id: ExprId) -> PResult<BasicBlock> {
239         parse_by_kind!(self, expr_id, _, "basic block",
240             ExprKind::VarRef { id } => Ok(self.block_map[id]),
241         )
242     }
243
244     fn parse_static(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
245         let expr_id = parse_by_kind!(self, expr_id, _, "static",
246             ExprKind::Deref { arg } => *arg,
247         );
248
249         parse_by_kind!(self, expr_id, expr, "static",
250             ExprKind::StaticRef { alloc_id, ty, .. } => {
251                 let const_val =
252                     ConstValue::Scalar(Scalar::from_pointer((*alloc_id).into(), &self.tcx));
253                 let literal = ConstantKind::Val(const_val, *ty);
254
255                 Ok(Operand::Constant(Box::new(Constant {
256                     span: expr.span,
257                     user_ty: None,
258                     literal
259                 })))
260             },
261         )
262     }
263
264     fn parse_integer_literal(&self, expr_id: ExprId) -> PResult<u128> {
265         parse_by_kind!(self, expr_id, expr, "constant",
266             ExprKind::Literal { .. }
267             | ExprKind::NamedConst { .. }
268             | ExprKind::NonHirLiteral { .. }
269             | ExprKind::ConstBlock { .. } => Ok({
270                 let value = as_constant_inner(expr, |_| None, self.tcx);
271                 value.literal.eval_bits(self.tcx, self.param_env, value.ty())
272             }),
273         )
274     }
275 }