]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
Auto merge of #105356 - JakobDegen:more-custom-mir, r=oli-obk
[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_retag", args) => {
16                 Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?)))
17             },
18             @call("mir_retag_raw", args) => {
19                 Ok(StatementKind::Retag(RetagKind::Raw, Box::new(self.parse_place(args[0])?)))
20             },
21             @call("mir_set_discriminant", args) => {
22                 let place = self.parse_place(args[0])?;
23                 let var = self.parse_integer_literal(args[1])? as u32;
24                 Ok(StatementKind::SetDiscriminant {
25                     place: Box::new(place),
26                     variant_index: VariantIdx::from_u32(var),
27                 })
28             },
29             ExprKind::Assign { lhs, rhs } => {
30                 let lhs = self.parse_place(*lhs)?;
31                 let rhs = self.parse_rvalue(*rhs)?;
32                 Ok(StatementKind::Assign(Box::new((lhs, rhs))))
33             },
34         )
35     }
36
37     pub fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> {
38         parse_by_kind!(self, expr_id, expr, "terminator",
39             @call("mir_return", _args) => {
40                 Ok(TerminatorKind::Return)
41             },
42             @call("mir_goto", args) => {
43                 Ok(TerminatorKind::Goto { target: self.parse_block(args[0])? } )
44             },
45             ExprKind::Match { scrutinee, arms } => {
46                 let discr = self.parse_operand(*scrutinee)?;
47                 self.parse_match(arms, expr.span).map(|t| TerminatorKind::SwitchInt { discr, targets: t })
48             },
49         )
50     }
51
52     fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> {
53         let Some((otherwise, rest)) = arms.split_last() else {
54             return Err(ParseError {
55                 span,
56                 item_description: format!("no arms"),
57                 expected: "at least one arm".to_string(),
58             })
59         };
60
61         let otherwise = &self.thir[*otherwise];
62         let PatKind::Wild = otherwise.pattern.kind else {
63             return Err(ParseError {
64                 span: otherwise.span,
65                 item_description: format!("{:?}", otherwise.pattern.kind),
66                 expected: "wildcard pattern".to_string(),
67             })
68         };
69         let otherwise = self.parse_block(otherwise.body)?;
70
71         let mut values = Vec::new();
72         let mut targets = Vec::new();
73         for arm in rest {
74             let arm = &self.thir[*arm];
75             let PatKind::Constant { value } = arm.pattern.kind else {
76                 return Err(ParseError {
77                     span: arm.pattern.span,
78                     item_description: format!("{:?}", arm.pattern.kind),
79                     expected: "constant pattern".to_string(),
80                 })
81             };
82             values.push(value.eval_bits(self.tcx, self.param_env, arm.pattern.ty));
83             targets.push(self.parse_block(arm.body)?);
84         }
85
86         Ok(SwitchTargets::new(values.into_iter().zip(targets), otherwise))
87     }
88
89     fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
90         parse_by_kind!(self, expr_id, _, "rvalue",
91             @call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
92             ExprKind::Borrow { borrow_kind, arg } => Ok(
93                 Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
94             ),
95             ExprKind::AddressOf { mutability, arg } => Ok(
96                 Rvalue::AddressOf(*mutability, self.parse_place(*arg)?)
97             ),
98             _ => self.parse_operand(expr_id).map(Rvalue::Use),
99         )
100     }
101
102     fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
103         parse_by_kind!(self, expr_id, expr, "operand",
104             @call("mir_move", args) => self.parse_place(args[0]).map(Operand::Move),
105             @call("mir_static", args) => self.parse_static(args[0]),
106             @call("mir_static_mut", args) => self.parse_static(args[0]),
107             ExprKind::Literal { .. }
108             | ExprKind::NamedConst { .. }
109             | ExprKind::NonHirLiteral { .. }
110             | ExprKind::ZstLiteral { .. }
111             | ExprKind::ConstParam { .. }
112             | ExprKind::ConstBlock { .. } => {
113                 Ok(Operand::Constant(Box::new(
114                     as_constant_inner(expr, |_| None, self.tcx)
115                 )))
116             },
117             _ => self.parse_place(expr_id).map(Operand::Copy),
118         )
119     }
120
121     fn parse_place(&self, expr_id: ExprId) -> PResult<Place<'tcx>> {
122         self.parse_place_inner(expr_id).map(|(x, _)| x)
123     }
124
125     fn parse_place_inner(&self, expr_id: ExprId) -> PResult<(Place<'tcx>, PlaceTy<'tcx>)> {
126         let (parent, proj) = parse_by_kind!(self, expr_id, expr, "place",
127             @call("mir_field", args) => {
128                 let (parent, ty) = self.parse_place_inner(args[0])?;
129                 let field = Field::from_u32(self.parse_integer_literal(args[1])? as u32);
130                 let field_ty = ty.field_ty(self.tcx, field);
131                 let proj = PlaceElem::Field(field, field_ty);
132                 let place = parent.project_deeper(&[proj], self.tcx);
133                 return Ok((place, PlaceTy::from_ty(field_ty)));
134             },
135             @call("mir_variant", args) => {
136                 (args[0], PlaceElem::Downcast(
137                     None,
138                     VariantIdx::from_u32(self.parse_integer_literal(args[1])? as u32)
139                 ))
140             },
141             ExprKind::Deref { arg } => {
142                 parse_by_kind!(self, *arg, _, "does not matter",
143                     @call("mir_make_place", args) => return self.parse_place_inner(args[0]),
144                     _ => (*arg, PlaceElem::Deref),
145                 )
146             },
147             ExprKind::Index { lhs, index } => (*lhs, PlaceElem::Index(self.parse_local(*index)?)),
148             ExprKind::Field { lhs, name: field, .. } => (*lhs, PlaceElem::Field(*field, expr.ty)),
149             _ => {
150                 let place = self.parse_local(expr_id).map(Place::from)?;
151                 return Ok((place, PlaceTy::from_ty(expr.ty)))
152             },
153         );
154         let (parent, ty) = self.parse_place_inner(parent)?;
155         let place = parent.project_deeper(&[proj], self.tcx);
156         let ty = ty.projection_ty(self.tcx, proj);
157         Ok((place, ty))
158     }
159
160     fn parse_local(&self, expr_id: ExprId) -> PResult<Local> {
161         parse_by_kind!(self, expr_id, _, "local",
162             ExprKind::VarRef { id } => Ok(self.local_map[id]),
163         )
164     }
165
166     fn parse_block(&self, expr_id: ExprId) -> PResult<BasicBlock> {
167         parse_by_kind!(self, expr_id, _, "basic block",
168             ExprKind::VarRef { id } => Ok(self.block_map[id]),
169         )
170     }
171
172     fn parse_static(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
173         let expr_id = parse_by_kind!(self, expr_id, _, "static",
174             ExprKind::Deref { arg } => *arg,
175         );
176
177         parse_by_kind!(self, expr_id, expr, "static",
178             ExprKind::StaticRef { alloc_id, ty, .. } => {
179                 let const_val =
180                     ConstValue::Scalar(Scalar::from_pointer((*alloc_id).into(), &self.tcx));
181                 let literal = ConstantKind::Val(const_val, *ty);
182
183                 Ok(Operand::Constant(Box::new(Constant {
184                     span: expr.span,
185                     user_ty: None,
186                     literal
187                 })))
188             },
189         )
190     }
191
192     fn parse_integer_literal(&self, expr_id: ExprId) -> PResult<u128> {
193         parse_by_kind!(self, expr_id, expr, "constant",
194             ExprKind::Literal { .. }
195             | ExprKind::NamedConst { .. }
196             | ExprKind::NonHirLiteral { .. }
197             | ExprKind::ConstBlock { .. } => Ok({
198                 let value = as_constant_inner(expr, |_| None, self.tcx);
199                 value.literal.eval_bits(self.tcx, self.param_env, value.ty())
200             }),
201         )
202     }
203 }