1use inkwell::{
2 basic_block::BasicBlock,
3 values::{BasicValue, BasicValueEnum, PhiValue},
4};
5use smallvec::SmallVec;
6use std::{
7 collections::VecDeque,
8 ops::{BitAnd, BitOr, BitOrAssign},
9};
10use wasmer_types::CompileError;
11
12#[derive(Debug)]
13#[allow(dead_code)]
14pub enum ControlFrame<'ctx> {
15 Block {
16 next: BasicBlock<'ctx>,
17 phis: SmallVec<[PhiValue<'ctx>; 1]>,
18 stack_size_snapshot: usize,
19 },
20 Loop {
21 body: BasicBlock<'ctx>,
22 next: BasicBlock<'ctx>,
23 phis: SmallVec<[PhiValue<'ctx>; 1]>,
24 loop_body_phis: SmallVec<[PhiValue<'ctx>; 1]>,
25 stack_size_snapshot: usize,
26 },
27 IfElse {
28 if_then: BasicBlock<'ctx>,
29 if_else: BasicBlock<'ctx>,
30 next: BasicBlock<'ctx>,
31 then_phis: SmallVec<[PhiValue<'ctx>; 1]>,
32 else_phis: SmallVec<[PhiValue<'ctx>; 1]>,
33 next_phis: SmallVec<[PhiValue<'ctx>; 1]>,
34 stack_size_snapshot: usize,
35 if_else_state: IfElseState,
36 },
37 Landingpad {
38 next: BasicBlock<'ctx>,
39 next_phis: SmallVec<[PhiValue<'ctx>; 1]>,
40 stack_size_snapshot: usize,
41 },
42}
43
44#[derive(Debug)]
45pub enum IfElseState {
46 If,
47 Else,
48}
49
50impl<'ctx> ControlFrame<'ctx> {
51 pub fn code_after(&self) -> &BasicBlock<'ctx> {
52 match self {
53 ControlFrame::Block { next, .. }
54 | ControlFrame::Loop { next, .. }
55 | ControlFrame::Landingpad { next, .. }
56 | ControlFrame::IfElse { next, .. } => next,
57 }
58 }
59
60 pub fn br_dest(&self) -> &BasicBlock<'ctx> {
61 match self {
62 ControlFrame::Block { next, .. }
63 | ControlFrame::IfElse { next, .. }
64 | ControlFrame::Landingpad { next, .. } => next,
65 ControlFrame::Loop { body, .. } => body,
66 }
67 }
68
69 pub fn phis(&self) -> &[PhiValue<'ctx>] {
70 match self {
71 ControlFrame::Block { phis, .. } | ControlFrame::Loop { phis, .. } => phis.as_slice(),
72 ControlFrame::IfElse { next_phis, .. } | ControlFrame::Landingpad { next_phis, .. } => {
73 next_phis.as_slice()
74 }
75 }
76 }
77
78 pub fn loop_body_phis(&self) -> &[PhiValue<'ctx>] {
80 match self {
81 ControlFrame::Loop { loop_body_phis, .. } => loop_body_phis.as_slice(),
82 _ => &[],
83 }
84 }
85
86 pub fn is_loop(&self) -> bool {
87 matches!(self, ControlFrame::Loop { .. })
88 }
89}
90
91#[derive(Debug, Default, Eq, PartialEq, Copy, Clone, Hash)]
92pub struct ExtraInfo {
93 state: u8,
94}
95impl ExtraInfo {
96 pub const fn pending_f32_nan() -> ExtraInfo {
104 ExtraInfo { state: 1 }
105 }
106
107 pub const fn pending_f64_nan() -> ExtraInfo {
115 ExtraInfo { state: 2 }
116 }
117
118 pub const fn arithmetic_f32() -> ExtraInfo {
121 ExtraInfo { state: 4 }
122 }
123
124 pub const fn arithmetic_f64() -> ExtraInfo {
127 ExtraInfo { state: 8 }
128 }
129
130 pub const fn has_pending_f32_nan(&self) -> bool {
131 self.state & ExtraInfo::pending_f32_nan().state != 0
132 }
133 pub const fn has_pending_f64_nan(&self) -> bool {
134 self.state & ExtraInfo::pending_f64_nan().state != 0
135 }
136 pub const fn is_arithmetic_f32(&self) -> bool {
137 self.state & ExtraInfo::arithmetic_f32().state != 0
138 }
139 pub const fn is_arithmetic_f64(&self) -> bool {
140 self.state & ExtraInfo::arithmetic_f64().state != 0
141 }
142
143 pub const fn strip_pending(&self) -> ExtraInfo {
144 ExtraInfo {
145 state: self.state
146 & !(ExtraInfo::pending_f32_nan().state | ExtraInfo::pending_f64_nan().state),
147 }
148 }
149}
150
151impl BitOr for ExtraInfo {
153 type Output = Result<Self, CompileError>;
154
155 fn bitor(self, other: Self) -> Self::Output {
156 if (self.has_pending_f32_nan() && other.has_pending_f64_nan())
157 || (self.has_pending_f64_nan() && other.has_pending_f32_nan())
158 {
159 return Err(CompileError::Codegen("Can't produce bitwise or of two different states if there are two different kinds of nan canonicalizations at the same time".to_string()));
160 }
161
162 Ok(ExtraInfo {
163 state: if self.is_arithmetic_f32() || other.is_arithmetic_f32() {
164 ExtraInfo::arithmetic_f32().state
165 } else if self.has_pending_f32_nan() || other.has_pending_f32_nan() {
166 ExtraInfo::pending_f32_nan().state
167 } else {
168 0
169 } + if self.is_arithmetic_f64() || other.is_arithmetic_f64() {
170 ExtraInfo::arithmetic_f64().state
171 } else if self.has_pending_f64_nan() || other.has_pending_f64_nan() {
172 ExtraInfo::pending_f64_nan().state
173 } else {
174 0
175 },
176 })
177 }
178}
179impl BitOrAssign for ExtraInfo {
180 fn bitor_assign(&mut self, other: Self) {
181 *self = (*self | other).unwrap();
182 }
183}
184
185impl BitAnd for ExtraInfo {
187 type Output = Result<Self, CompileError>;
188 fn bitand(self, other: Self) -> Self::Output {
189 debug_assert!(
191 self.has_pending_f32_nan() == other.has_pending_f32_nan()
192 || self.is_arithmetic_f32()
193 || other.is_arithmetic_f32()
194 );
195 debug_assert!(
196 self.has_pending_f64_nan() == other.has_pending_f64_nan()
197 || self.is_arithmetic_f64()
198 || other.is_arithmetic_f64()
199 );
200 let info = match (
201 self.is_arithmetic_f32() && other.is_arithmetic_f32(),
202 self.is_arithmetic_f64() && other.is_arithmetic_f64(),
203 ) {
204 (false, false) => Default::default(),
205 (true, false) => ExtraInfo::arithmetic_f32(),
206 (false, true) => ExtraInfo::arithmetic_f64(),
207 (true, true) => (ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64())?,
208 };
209 match (self.has_pending_f32_nan(), self.has_pending_f64_nan()) {
210 (false, false) => Ok(info),
211 (true, false) => info | ExtraInfo::pending_f32_nan(),
212 (false, true) => info | ExtraInfo::pending_f64_nan(),
213 (true, true) => unreachable!("Can't form ExtraInfo with two pending canonicalizations"),
214 }
215 }
216}
217
218#[derive(Debug, Clone, Copy)]
219pub struct TagCatchInfo<'ctx> {
220 pub tag: u32,
221 pub catch_block: BasicBlock<'ctx>,
223 pub wasmer_exc_phi: Option<PhiValue<'ctx>>,
225 pub uw_exc_ptr_phi: Option<PhiValue<'ctx>>,
228}
229
230#[derive(Debug)]
231pub struct Landingpad<'ctx> {
232 pub lpad_block: Option<BasicBlock<'ctx>>,
236 pub tags: Vec<TagCatchInfo<'ctx>>,
238}
239
240#[derive(Debug)]
241pub struct State<'ctx> {
242 pub stack: Vec<(BasicValueEnum<'ctx>, ExtraInfo)>,
243 pub control_stack: Vec<ControlFrame<'ctx>>,
244 pub landingpads: VecDeque<Landingpad<'ctx>>,
245 pub reachable: bool,
246}
247
248impl<'ctx> State<'ctx> {
249 pub fn new() -> Self {
250 Self {
251 stack: vec![],
252 control_stack: vec![],
253 reachable: true,
254 landingpads: VecDeque::new(),
255 }
256 }
257
258 pub fn has_control_frames(&self) -> bool {
259 !self.control_stack.is_empty()
260 }
261
262 pub fn reset_stack(&mut self, frame: &ControlFrame<'ctx>) {
263 let stack_size_snapshot = match frame {
264 ControlFrame::Block {
265 stack_size_snapshot,
266 ..
267 }
268 | ControlFrame::Loop {
269 stack_size_snapshot,
270 ..
271 }
272 | ControlFrame::IfElse {
273 stack_size_snapshot,
274 ..
275 }
276 | ControlFrame::Landingpad {
277 stack_size_snapshot,
278 ..
279 } => *stack_size_snapshot,
280 };
281 self.stack.truncate(stack_size_snapshot);
282 }
283
284 pub fn outermost_frame(&self) -> Result<&ControlFrame<'ctx>, CompileError> {
285 self.control_stack.first().ok_or_else(|| {
286 CompileError::Codegen("outermost_frame: invalid control stack depth".to_string())
287 })
288 }
289
290 pub fn frame_at_depth(&self, depth: u32) -> Result<&ControlFrame<'ctx>, CompileError> {
291 let index = self
292 .control_stack
293 .len()
294 .checked_sub(1 + (depth as usize))
295 .ok_or_else(|| {
296 CompileError::Codegen("frame_at_depth: invalid control stack depth".to_string())
297 })?;
298 Ok(&self.control_stack[index])
299 }
300
301 pub fn frame_at_depth_mut(
302 &mut self,
303 depth: u32,
304 ) -> Result<&mut ControlFrame<'ctx>, CompileError> {
305 let index = self
306 .control_stack
307 .len()
308 .checked_sub(1 + (depth as usize))
309 .ok_or_else(|| {
310 CompileError::Codegen("frame_at_depth_mut: invalid control stack depth".to_string())
311 })?;
312 Ok(&mut self.control_stack[index])
313 }
314
315 pub fn pop_frame(&mut self) -> Result<ControlFrame<'ctx>, CompileError> {
316 self.control_stack.pop().ok_or_else(|| {
317 CompileError::Codegen("pop_frame: cannot pop from control stack".to_string())
318 })
319 }
320
321 pub fn push1<T: BasicValue<'ctx>>(&mut self, value: T) {
322 self.push1_extra(value, Default::default());
323 }
324
325 pub fn push1_extra<T: BasicValue<'ctx>>(&mut self, value: T, info: ExtraInfo) {
326 self.stack.push((value.as_basic_value_enum(), info));
327 }
328
329 pub fn pop1(&mut self) -> Result<BasicValueEnum<'ctx>, CompileError> {
330 Ok(self.pop1_extra()?.0)
331 }
332
333 pub fn pop1_extra(&mut self) -> Result<(BasicValueEnum<'ctx>, ExtraInfo), CompileError> {
334 self.stack
335 .pop()
336 .ok_or_else(|| CompileError::Codegen("pop1_extra: invalid value stack".to_string()))
337 }
338
339 pub fn pop2(&mut self) -> Result<(BasicValueEnum<'ctx>, BasicValueEnum<'ctx>), CompileError> {
340 let v2 = self.pop1()?;
341 let v1 = self.pop1()?;
342 Ok((v1, v2))
343 }
344
345 #[allow(clippy::type_complexity)]
346 pub fn pop2_extra(
347 &mut self,
348 ) -> Result<
349 (
350 (BasicValueEnum<'ctx>, ExtraInfo),
351 (BasicValueEnum<'ctx>, ExtraInfo),
352 ),
353 CompileError,
354 > {
355 let v2 = self.pop1_extra()?;
356 let v1 = self.pop1_extra()?;
357 Ok((v1, v2))
358 }
359
360 pub fn pop3(
361 &mut self,
362 ) -> Result<
363 (
364 BasicValueEnum<'ctx>,
365 BasicValueEnum<'ctx>,
366 BasicValueEnum<'ctx>,
367 ),
368 CompileError,
369 > {
370 let v3 = self.pop1()?;
371 let v2 = self.pop1()?;
372 let v1 = self.pop1()?;
373 Ok((v1, v2, v3))
374 }
375
376 #[allow(clippy::type_complexity)]
377 pub fn pop3_extra(
378 &mut self,
379 ) -> Result<
380 (
381 (BasicValueEnum<'ctx>, ExtraInfo),
382 (BasicValueEnum<'ctx>, ExtraInfo),
383 (BasicValueEnum<'ctx>, ExtraInfo),
384 ),
385 CompileError,
386 > {
387 let v3 = self.pop1_extra()?;
388 let v2 = self.pop1_extra()?;
389 let v1 = self.pop1_extra()?;
390 Ok((v1, v2, v3))
391 }
392
393 pub fn peek1_extra(&self) -> Result<(BasicValueEnum<'ctx>, ExtraInfo), CompileError> {
394 let index =
395 self.stack.len().checked_sub(1).ok_or_else(|| {
396 CompileError::Codegen("peek1_extra: invalid value stack".to_string())
397 })?;
398 Ok(self.stack[index])
399 }
400
401 pub fn peekn(&self, n: usize) -> Result<Vec<BasicValueEnum<'ctx>>, CompileError> {
402 Ok(self.peekn_extra(n)?.iter().map(|x| x.0).collect())
403 }
404
405 pub fn peekn_extra(
406 &self,
407 n: usize,
408 ) -> Result<&[(BasicValueEnum<'ctx>, ExtraInfo)], CompileError> {
409 let index =
410 self.stack.len().checked_sub(n).ok_or_else(|| {
411 CompileError::Codegen("peekn_extra: invalid value stack".to_string())
412 })?;
413 Ok(&self.stack[index..])
414 }
415
416 pub fn popn_save_extra(
417 &mut self,
418 n: usize,
419 ) -> Result<Vec<(BasicValueEnum<'ctx>, ExtraInfo)>, CompileError> {
420 let v = self.peekn_extra(n)?.to_vec();
421 self.popn(n)?;
422 Ok(v)
423 }
424
425 pub fn popn(&mut self, n: usize) -> Result<(), CompileError> {
426 let index = self
427 .stack
428 .len()
429 .checked_sub(n)
430 .ok_or_else(|| CompileError::Codegen("popn: invalid value stack".to_string()))?;
431
432 self.stack.truncate(index);
433 Ok(())
434 }
435
436 pub fn push_block(
437 &mut self,
438 next: BasicBlock<'ctx>,
439 phis: SmallVec<[PhiValue<'ctx>; 1]>,
440 num_inputs: usize,
441 ) {
442 self.control_stack.push(ControlFrame::Block {
443 next,
444 phis,
445 stack_size_snapshot: self
446 .stack
447 .len()
448 .checked_sub(num_inputs)
449 .expect("Internal codegen error: not enough inputs on stack"),
450 });
451 }
452
453 pub fn push_loop(
454 &mut self,
455 body: BasicBlock<'ctx>,
456 next: BasicBlock<'ctx>,
457 loop_body_phis: SmallVec<[PhiValue<'ctx>; 1]>,
458 phis: SmallVec<[PhiValue<'ctx>; 1]>,
459 num_inputs: usize,
460 ) {
461 self.control_stack.push(ControlFrame::Loop {
462 body,
463 next,
464 loop_body_phis,
465 phis,
466 stack_size_snapshot: self
467 .stack
468 .len()
469 .checked_sub(num_inputs)
470 .expect("Internal codegen error: not enough inputs on stack"),
471 });
472 }
473
474 #[allow(clippy::too_many_arguments)]
475 pub fn push_if(
476 &mut self,
477 if_then: BasicBlock<'ctx>,
478 if_else: BasicBlock<'ctx>,
479 next: BasicBlock<'ctx>,
480 then_phis: SmallVec<[PhiValue<'ctx>; 1]>,
481 else_phis: SmallVec<[PhiValue<'ctx>; 1]>,
482 next_phis: SmallVec<[PhiValue<'ctx>; 1]>,
483 num_inputs: usize,
484 ) {
485 self.control_stack.push(ControlFrame::IfElse {
486 if_then,
487 if_else,
488 next,
489 then_phis,
490 else_phis,
491 next_phis,
492 if_else_state: IfElseState::If,
493 stack_size_snapshot: self
494 .stack
495 .len()
496 .checked_sub(num_inputs)
497 .expect("Internal codegen error: not enough inputs on stack"),
498 });
499 }
500
501 pub fn push_landingpad(
502 &mut self,
503 lpad_block: Option<BasicBlock<'ctx>>,
504 next: BasicBlock<'ctx>,
505 next_phis: SmallVec<[PhiValue<'ctx>; 1]>,
506 tags: &[TagCatchInfo<'ctx>],
507 num_inputs: usize,
508 ) {
509 self.control_stack.push(ControlFrame::Landingpad {
510 next,
511 next_phis,
512 stack_size_snapshot: self
513 .stack
514 .len()
515 .checked_sub(num_inputs)
516 .expect("Internal codegen error: not enough inputs on stack"),
517 });
518
519 self.landingpads.push_back(Landingpad {
520 lpad_block,
521 tags: tags.to_vec(),
522 })
523 }
524
525 pub(crate) fn get_innermost_landingpad(&mut self) -> Option<BasicBlock<'ctx>> {
531 self.landingpads
532 .iter()
533 .rev()
534 .filter_map(|v| v.lpad_block)
535 .next()
536 }
537
538 pub(crate) fn pop_landingpad(&mut self) -> bool {
539 self.landingpads.pop_back().is_some()
540 }
541}