1use crate::meta::Span;
3use crate::ullbc_ast::*;
4use std::mem;
5
6impl SwitchTargets {
7 pub fn get_targets(&self) -> Vec<BlockId> {
8 match self {
9 SwitchTargets::If(then_tgt, else_tgt) => {
10 vec![*then_tgt, *else_tgt]
11 }
12 SwitchTargets::SwitchInt(_, targets, otherwise) => {
13 let mut all_targets = vec![];
14 for (_, target) in targets {
15 all_targets.push(*target);
16 }
17 all_targets.push(*otherwise);
18 all_targets
19 }
20 }
21 }
22}
23
24impl Statement {
25 pub fn new(span: Span, kind: StatementKind) -> Self {
26 Statement {
27 span,
28 kind,
29 comments_before: vec![],
30 }
31 }
32}
33
34impl Terminator {
35 pub fn new(span: Span, kind: TerminatorKind) -> Self {
36 Terminator {
37 span,
38 kind,
39 comments_before: vec![],
40 }
41 }
42 pub fn goto(span: Span, target: BlockId) -> Self {
43 Self::new(span, TerminatorKind::Goto { target })
44 }
45 pub fn is_error(&self) -> bool {
47 use TerminatorKind::*;
48 match &self.kind {
49 Abort(..) => true,
50 Goto { .. } | Switch { .. } | Return | Call { .. } | Drop { .. } | UnwindResume => {
51 false
52 }
53 }
54 }
55
56 pub fn into_block(self) -> BlockData {
57 BlockData {
58 statements: vec![],
59 terminator: self,
60 }
61 }
62}
63
64impl BlockData {
65 pub fn new_goto(span: Span, target: BlockId) -> Self {
67 BlockData {
68 statements: vec![],
69 terminator: Terminator::goto(span, target),
70 }
71 }
72
73 pub fn targets(&self) -> Vec<BlockId> {
74 match &self.terminator.kind {
75 TerminatorKind::Goto { target } => {
76 vec![*target]
77 }
78 TerminatorKind::Switch { targets, .. } => targets.get_targets(),
79 TerminatorKind::Call {
80 target, on_unwind, ..
81 }
82 | TerminatorKind::Drop {
83 target, on_unwind, ..
84 } => vec![*target, *on_unwind],
85 TerminatorKind::Abort(..) | TerminatorKind::Return | TerminatorKind::UnwindResume => {
86 vec![]
87 }
88 }
89 }
90
91 pub fn targets_ignoring_unwind(&self) -> Vec<BlockId> {
92 match &self.terminator.kind {
93 TerminatorKind::Goto { target } => {
94 vec![*target]
95 }
96 TerminatorKind::Switch { targets, .. } => targets.get_targets(),
97 TerminatorKind::Call { target, .. } | TerminatorKind::Drop { target, .. } => {
98 vec![*target]
99 }
100 TerminatorKind::Abort(..) | TerminatorKind::Return | TerminatorKind::UnwindResume => {
101 vec![]
102 }
103 }
104 }
105
106 pub fn transform_operands<F: FnMut(&Span, &mut Vec<Statement>, &mut Operand)>(
108 &mut self,
109 mut f: F,
110 ) {
111 for mut st in mem::take(&mut self.statements) {
113 st.kind
114 .dyn_visit_in_body_mut(|op: &mut Operand| f(&st.span, &mut self.statements, op));
115 self.statements.push(st)
117 }
118
119 self.terminator
121 .kind
122 .dyn_visit_in_body_mut(|op: &mut Operand| {
123 f(&self.terminator.span, &mut self.statements, op)
124 });
125 }
126
127 pub fn transform<F: FnMut(&mut Statement) -> Vec<Statement>>(&mut self, mut f: F) {
133 self.transform_sequences_bwd(|slice| {
134 let new_statements = f(&mut slice[0]);
135 if new_statements.is_empty() {
136 vec![]
137 } else {
138 vec![(0, new_statements)]
139 }
140 });
141 }
142
143 fn transform_sequences<F>(&mut self, mut f: F, forward: bool)
145 where
146 F: FnMut(&mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
147 {
148 let mut to_insert = vec![];
149 let mut final_len = self.statements.len();
150 if forward {
151 for i in 0..self.statements.len() {
152 let new_to_insert = f(&mut self.statements[i..]);
153 to_insert.extend(new_to_insert.into_iter().map(|(j, stmts)| {
154 final_len += stmts.len();
155 (i + j, stmts)
156 }));
157 }
158 } else {
159 for i in (0..self.statements.len()).rev() {
160 let new_to_insert = f(&mut self.statements[i..]);
161 to_insert.extend(new_to_insert.into_iter().map(|(j, stmts)| {
162 final_len += stmts.len();
163 (i + j, stmts)
164 }));
165 }
166 }
167 if !to_insert.is_empty() {
168 to_insert.sort_by_key(|(i, _)| *i);
169 to_insert.reverse();
171 let old_statements = mem::replace(&mut self.statements, Vec::with_capacity(final_len));
173 for (i, stmt) in old_statements.into_iter().enumerate() {
174 while let Some((j, _)) = to_insert.last()
175 && *j == i
176 {
177 let (_, mut stmts) = to_insert.pop().unwrap();
178 self.statements.append(&mut stmts);
179 }
180 self.statements.push(stmt);
181 }
182 }
183 }
184
185 pub fn transform_sequences_fwd<F>(&mut self, f: F)
191 where
192 F: FnMut(&mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
193 {
194 self.transform_sequences(f, true);
195 }
196
197 pub fn transform_sequences_bwd<F>(&mut self, f: F)
203 where
204 F: FnMut(&mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
205 {
206 self.transform_sequences(f, false);
207 }
208}
209
210impl ExprBody {
211 pub fn transform_sequences_fwd<F>(&mut self, mut f: F)
212 where
213 F: FnMut(&mut Locals, &mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
214 {
215 for block in &mut self.body {
216 block.transform_sequences_fwd(|seq| f(&mut self.locals, seq));
217 }
218 }
219
220 pub fn transform_sequences_bwd<F>(&mut self, mut f: F)
221 where
222 F: FnMut(&mut Locals, &mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
223 {
224 for block in &mut self.body {
225 block.transform_sequences_bwd(|seq| f(&mut self.locals, seq));
226 }
227 }
228
229 pub fn visit_statements<F: FnMut(&mut Statement)>(&mut self, mut f: F) {
231 for block in self.body.iter_mut().rev() {
232 for st in block.statements.iter_mut().rev() {
233 f(st);
234 }
235 }
236 }
237}
238
239pub struct BodyBuilder {
241 pub span: Span,
243 pub body: ExprBody,
245 pub current_block: BlockId,
247 pub unwind_block: Option<BlockId>,
249}
250
251fn mk_block(span: Span, term: TerminatorKind) -> BlockData {
252 BlockData {
253 statements: vec![],
254 terminator: Terminator::new(span, term),
255 }
256}
257
258impl BodyBuilder {
259 pub fn new(span: Span, arg_count: usize) -> Self {
260 let mut body: ExprBody = GExprBody {
261 span,
262 locals: Locals::new(arg_count),
263 comments: vec![],
264 body: Vector::new(),
265 };
266 let current_block = body.body.push(BlockData {
267 statements: Default::default(),
268 terminator: Terminator::new(span, TerminatorKind::Return),
269 });
270 Self {
271 span,
272 body,
273 current_block,
274 unwind_block: None,
275 }
276 }
277
278 pub fn build(self) -> ExprBody {
280 self.body
281 }
282
283 pub fn new_var(&mut self, name: Option<String>, ty: Ty) -> Place {
286 let place = self.body.locals.new_var(name, ty);
287 let local_id = place.as_local().unwrap();
288 if !self.body.locals.is_return_or_arg(local_id) {
289 self.push_statement(StatementKind::StorageLive(local_id));
290 }
291 place
292 }
293
294 fn current_block(&mut self) -> &mut BlockData {
296 &mut self.body.body[self.current_block]
297 }
298
299 pub fn push_statement(&mut self, kind: StatementKind) {
300 let st = Statement::new(self.span, kind);
301 self.current_block().statements.push(st);
302 }
303
304 fn unwind_block(&mut self) -> BlockId {
305 *self.unwind_block.get_or_insert_with(|| {
306 self.body
307 .body
308 .push(mk_block(self.span, TerminatorKind::UnwindResume))
309 })
310 }
311
312 pub fn call(&mut self, call: Call) {
313 let next_block = self
314 .body
315 .body
316 .push(mk_block(self.span, TerminatorKind::Return));
317 let term = TerminatorKind::Call {
318 target: next_block,
319 call,
320 on_unwind: self.unwind_block(),
321 };
322 self.current_block().terminator.kind = term;
323 self.current_block = next_block;
324 }
325
326 pub fn insert_drop(&mut self, place: Place, tref: TraitRef) {
327 let next_block = self
328 .body
329 .body
330 .push(mk_block(self.span, TerminatorKind::Return));
331 let term = TerminatorKind::Drop {
332 place: place,
333 tref: tref,
334 target: next_block,
335 on_unwind: self.unwind_block(),
336 };
337 self.current_block().terminator.kind = term;
338 self.current_block = next_block;
339 }
340}