/src/wasmer/lib/compiler-llvm/src/translator/state.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use inkwell::{ |
2 | | basic_block::BasicBlock, |
3 | | values::{BasicValue, BasicValueEnum, PhiValue}, |
4 | | }; |
5 | | use smallvec::SmallVec; |
6 | | use std::ops::{BitAnd, BitOr, BitOrAssign}; |
7 | | use wasmer_types::CompileError; |
8 | | |
9 | | #[derive(Debug)] |
10 | | pub enum ControlFrame<'ctx> { |
11 | | Block { |
12 | | next: BasicBlock<'ctx>, |
13 | | phis: SmallVec<[PhiValue<'ctx>; 1]>, |
14 | | stack_size_snapshot: usize, |
15 | | }, |
16 | | Loop { |
17 | | body: BasicBlock<'ctx>, |
18 | | next: BasicBlock<'ctx>, |
19 | | phis: SmallVec<[PhiValue<'ctx>; 1]>, |
20 | | loop_body_phis: SmallVec<[PhiValue<'ctx>; 1]>, |
21 | | stack_size_snapshot: usize, |
22 | | }, |
23 | | IfElse { |
24 | | if_then: BasicBlock<'ctx>, |
25 | | if_else: BasicBlock<'ctx>, |
26 | | next: BasicBlock<'ctx>, |
27 | | then_phis: SmallVec<[PhiValue<'ctx>; 1]>, |
28 | | else_phis: SmallVec<[PhiValue<'ctx>; 1]>, |
29 | | next_phis: SmallVec<[PhiValue<'ctx>; 1]>, |
30 | | stack_size_snapshot: usize, |
31 | | if_else_state: IfElseState, |
32 | | }, |
33 | | } |
34 | | |
35 | | #[derive(Debug)] |
36 | | pub enum IfElseState { |
37 | | If, |
38 | | Else, |
39 | | } |
40 | | |
41 | | impl<'ctx> ControlFrame<'ctx> { |
42 | 426k | pub fn code_after(&self) -> &BasicBlock<'ctx> { |
43 | 426k | match self { |
44 | 291k | ControlFrame::Block { ref next, .. } |
45 | 123k | | ControlFrame::Loop { ref next, .. } |
46 | 426k | | ControlFrame::IfElse { ref next, .. } => next, |
47 | 426k | } |
48 | 426k | } |
49 | | |
50 | 21.1k | pub fn br_dest(&self) -> &BasicBlock<'ctx> { |
51 | 21.1k | match self { |
52 | 15.1k | ControlFrame::Block { ref next, .. } | ControlFrame::IfElse { ref next, .. } => next, |
53 | 5.95k | ControlFrame::Loop { ref body, .. } => body, |
54 | | } |
55 | 21.1k | } |
56 | | |
57 | 442k | pub fn phis(&self) -> &[PhiValue<'ctx>] { |
58 | 442k | match self { |
59 | 306k | ControlFrame::Block { ref phis, .. } | ControlFrame::Loop { ref phis, .. } => { |
60 | 429k | phis.as_slice() |
61 | | } |
62 | 13.0k | ControlFrame::IfElse { ref next_phis, .. } => next_phis.as_slice(), |
63 | | } |
64 | 442k | } |
65 | | |
66 | | /// PHI nodes for stack values in the loop body. |
67 | 5.95k | pub fn loop_body_phis(&self) -> &[PhiValue<'ctx>] { |
68 | 5.95k | match self { |
69 | 0 | ControlFrame::Block { .. } | ControlFrame::IfElse { .. } => &[], |
70 | | ControlFrame::Loop { |
71 | 5.95k | ref loop_body_phis, .. |
72 | 5.95k | } => loop_body_phis.as_slice(), |
73 | | } |
74 | 5.95k | } |
75 | | |
76 | 16.0k | pub fn is_loop(&self) -> bool { |
77 | 16.0k | matches!(self, ControlFrame::Loop { .. }) |
78 | 16.0k | } |
79 | | } |
80 | | |
81 | | #[derive(Debug, Default, Eq, PartialEq, Copy, Clone, Hash)] |
82 | | pub struct ExtraInfo { |
83 | | state: u8, |
84 | | } |
85 | | impl ExtraInfo { |
86 | | // This value is required to be arithmetic 32-bit NaN (or 32x4) by the WAsm |
87 | | // machine, but which might not be in the LLVM value. The conversion to |
88 | | // arithmetic NaN is pending. It is required for correctness. |
89 | | // |
90 | | // When applied to a 64-bit value, this flag has no meaning and must be |
91 | | // ignored. It may be set in such cases to allow for common handling of |
92 | | // 32 and 64-bit operations. |
93 | 1.26M | pub const fn pending_f32_nan() -> ExtraInfo { |
94 | 1.26M | ExtraInfo { state: 1 } |
95 | 1.26M | } |
96 | | |
97 | | // This value is required to be arithmetic 64-bit NaN (or 64x2) by the WAsm |
98 | | // machine, but which might not be in the LLVM value. The conversion to |
99 | | // arithmetic NaN is pending. It is required for correctness. |
100 | | // |
101 | | // When applied to a 32-bit value, this flag has no meaning and must be |
102 | | // ignored. It may be set in such cases to allow for common handling of |
103 | | // 32 and 64-bit operations. |
104 | 1.33M | pub const fn pending_f64_nan() -> ExtraInfo { |
105 | 1.33M | ExtraInfo { state: 2 } |
106 | 1.33M | } |
107 | | |
108 | | // This value either does not contain a 32-bit NaN, or it contains an |
109 | | // arithmetic NaN. In SIMD, applies to all 4 lanes. |
110 | 600k | pub const fn arithmetic_f32() -> ExtraInfo { |
111 | 600k | ExtraInfo { state: 4 } |
112 | 600k | } |
113 | | |
114 | | // This value either does not contain a 64-bit NaN, or it contains an |
115 | | // arithmetic NaN. In SIMD, applies to both lanes. |
116 | 535k | pub const fn arithmetic_f64() -> ExtraInfo { |
117 | 535k | ExtraInfo { state: 8 } |
118 | 535k | } |
119 | | |
120 | 1.03M | pub const fn has_pending_f32_nan(&self) -> bool { |
121 | 1.03M | self.state & ExtraInfo::pending_f32_nan().state != 0 |
122 | 1.03M | } |
123 | 1.04M | pub const fn has_pending_f64_nan(&self) -> bool { |
124 | 1.04M | self.state & ExtraInfo::pending_f64_nan().state != 0 |
125 | 1.04M | } |
126 | 340k | pub const fn is_arithmetic_f32(&self) -> bool { |
127 | 340k | self.state & ExtraInfo::arithmetic_f32().state != 0 |
128 | 340k | } |
129 | 376k | pub const fn is_arithmetic_f64(&self) -> bool { |
130 | 376k | self.state & ExtraInfo::arithmetic_f64().state != 0 |
131 | 376k | } |
132 | | |
133 | 90.9k | pub const fn strip_pending(&self) -> ExtraInfo { |
134 | 90.9k | ExtraInfo { |
135 | 90.9k | state: self.state |
136 | 90.9k | & !(ExtraInfo::pending_f32_nan().state | ExtraInfo::pending_f64_nan().state), |
137 | 90.9k | } |
138 | 90.9k | } |
139 | | } |
140 | | |
141 | | // Union two ExtraInfos. |
142 | | impl BitOr for ExtraInfo { |
143 | | type Output = Self; |
144 | | |
145 | 189k | fn bitor(self, other: Self) -> Self { |
146 | 189k | debug_assert!(!(self.has_pending_f32_nan() && other.has_pending_f64_nan())); |
147 | 189k | debug_assert!(!(self.has_pending_f64_nan() && other.has_pending_f32_nan())); |
148 | | ExtraInfo { |
149 | 189k | state: if self.is_arithmetic_f32() || other.is_arithmetic_f32() { |
150 | 47.8k | ExtraInfo::arithmetic_f32().state |
151 | 141k | } else if self.has_pending_f32_nan() || other.has_pending_f32_nan() { |
152 | 46.8k | ExtraInfo::pending_f32_nan().state |
153 | | } else { |
154 | 95.1k | 0 |
155 | 189k | } + if self.is_arithmetic_f64() || other.is_arithmetic_f64() { |
156 | 27.1k | ExtraInfo::arithmetic_f64().state |
157 | 162k | } else if self.has_pending_f64_nan() || other.has_pending_f64_nan() { |
158 | 84.0k | ExtraInfo::pending_f64_nan().state |
159 | | } else { |
160 | 78.6k | 0 |
161 | | }, |
162 | | } |
163 | 189k | } |
164 | | } |
165 | | impl BitOrAssign for ExtraInfo { |
166 | 23 | fn bitor_assign(&mut self, other: Self) { |
167 | 23 | *self = *self | other; |
168 | 23 | } |
169 | | } |
170 | | |
171 | | // Intersection for ExtraInfo. |
172 | | impl BitAnd for ExtraInfo { |
173 | | type Output = Self; |
174 | 7.52k | fn bitand(self, other: Self) -> Self { |
175 | 7.52k | // Pending canonicalizations are not safe to discard, or even reorder. |
176 | 7.52k | debug_assert!( |
177 | 0 | self.has_pending_f32_nan() == other.has_pending_f32_nan() |
178 | 0 | || self.is_arithmetic_f32() |
179 | 0 | || other.is_arithmetic_f32() |
180 | | ); |
181 | 7.52k | debug_assert!( |
182 | 0 | self.has_pending_f64_nan() == other.has_pending_f64_nan() |
183 | 0 | || self.is_arithmetic_f64() |
184 | 0 | || other.is_arithmetic_f64() |
185 | | ); |
186 | 7.52k | let info = match ( |
187 | 7.52k | self.is_arithmetic_f32() && other.is_arithmetic_f32(), |
188 | 7.52k | self.is_arithmetic_f64() && other.is_arithmetic_f64(), |
189 | | ) { |
190 | 7.14k | (false, false) => Default::default(), |
191 | 210 | (true, false) => ExtraInfo::arithmetic_f32(), |
192 | 160 | (false, true) => ExtraInfo::arithmetic_f64(), |
193 | 7 | (true, true) => ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), |
194 | | }; |
195 | 7.52k | match (self.has_pending_f32_nan(), self.has_pending_f64_nan()) { |
196 | 7.52k | (false, false) => info, |
197 | 0 | (true, false) => info | ExtraInfo::pending_f32_nan(), |
198 | 0 | (false, true) => info | ExtraInfo::pending_f64_nan(), |
199 | 0 | (true, true) => unreachable!("Can't form ExtraInfo with two pending canonicalizations"), |
200 | | } |
201 | 7.52k | } |
202 | | } |
203 | | |
204 | | #[derive(Debug)] |
205 | | pub struct State<'ctx> { |
206 | | pub stack: Vec<(BasicValueEnum<'ctx>, ExtraInfo)>, |
207 | | control_stack: Vec<ControlFrame<'ctx>>, |
208 | | |
209 | | pub reachable: bool, |
210 | | } |
211 | | |
212 | | impl<'ctx> State<'ctx> { |
213 | 101k | pub fn new() -> Self { |
214 | 101k | Self { |
215 | 101k | stack: vec![], |
216 | 101k | control_stack: vec![], |
217 | 101k | reachable: true, |
218 | 101k | } |
219 | 101k | } |
220 | | |
221 | 3.58M | pub fn has_control_frames(&self) -> bool { |
222 | 3.58M | !self.control_stack.is_empty() |
223 | 3.58M | } |
224 | | |
225 | 274k | pub fn reset_stack(&mut self, frame: &ControlFrame<'ctx>) { |
226 | 274k | let stack_size_snapshot = match frame { |
227 | | ControlFrame::Block { |
228 | 184k | stack_size_snapshot, |
229 | | .. |
230 | | } |
231 | | | ControlFrame::Loop { |
232 | 84.2k | stack_size_snapshot, |
233 | | .. |
234 | | } |
235 | | | ControlFrame::IfElse { |
236 | 6.21k | stack_size_snapshot, |
237 | | .. |
238 | 274k | } => *stack_size_snapshot, |
239 | 274k | }; |
240 | 274k | self.stack.truncate(stack_size_snapshot); |
241 | 274k | } |
242 | | |
243 | 10.2k | pub fn outermost_frame(&self) -> Result<&ControlFrame<'ctx>, CompileError> { |
244 | 10.2k | self.control_stack.get(0).ok_or_else(|| { |
245 | 0 | CompileError::Codegen("outermost_frame: invalid control stack depth".to_string()) |
246 | 10.2k | }) |
247 | 10.2k | } |
248 | | |
249 | 29.9k | pub fn frame_at_depth(&self, depth: u32) -> Result<&ControlFrame<'ctx>, CompileError> { |
250 | 29.9k | let index = self |
251 | 29.9k | .control_stack |
252 | 29.9k | .len() |
253 | 29.9k | .checked_sub(1 + (depth as usize)) |
254 | 29.9k | .ok_or_else(|| { |
255 | 0 | CompileError::Codegen("frame_at_depth: invalid control stack depth".to_string()) |
256 | 29.9k | })?; |
257 | 29.9k | Ok(&self.control_stack[index]) |
258 | 29.9k | } |
259 | | |
260 | 5.23k | pub fn frame_at_depth_mut( |
261 | 5.23k | &mut self, |
262 | 5.23k | depth: u32, |
263 | 5.23k | ) -> Result<&mut ControlFrame<'ctx>, CompileError> { |
264 | 5.23k | let index = self |
265 | 5.23k | .control_stack |
266 | 5.23k | .len() |
267 | 5.23k | .checked_sub(1 + (depth as usize)) |
268 | 5.23k | .ok_or_else(|| { |
269 | 0 | CompileError::Codegen("frame_at_depth_mut: invalid control stack depth".to_string()) |
270 | 5.23k | })?; |
271 | 5.23k | Ok(&mut self.control_stack[index]) |
272 | 5.23k | } |
273 | | |
274 | 274k | pub fn pop_frame(&mut self) -> Result<ControlFrame<'ctx>, CompileError> { |
275 | 274k | self.control_stack.pop().ok_or_else(|| { |
276 | 0 | CompileError::Codegen("pop_frame: cannot pop from control stack".to_string()) |
277 | 274k | }) |
278 | 274k | } |
279 | | |
280 | 999k | pub fn push1<T: BasicValue<'ctx>>(&mut self, value: T) { |
281 | 999k | self.push1_extra(value, Default::default()); |
282 | 999k | } <wasmer_compiler_llvm::translator::state::State>::push1::<inkwell::values::enums::BasicValueEnum> Line | Count | Source | 280 | 685k | pub fn push1<T: BasicValue<'ctx>>(&mut self, value: T) { | 281 | 685k | self.push1_extra(value, Default::default()); | 282 | 685k | } |
<wasmer_compiler_llvm::translator::state::State>::push1::<inkwell::values::int_value::IntValue> Line | Count | Source | 280 | 266k | pub fn push1<T: BasicValue<'ctx>>(&mut self, value: T) { | 281 | 266k | self.push1_extra(value, Default::default()); | 282 | 266k | } |
<wasmer_compiler_llvm::translator::state::State>::push1::<inkwell::values::float_value::FloatValue> Line | Count | Source | 280 | 47.0k | pub fn push1<T: BasicValue<'ctx>>(&mut self, value: T) { | 281 | 47.0k | self.push1_extra(value, Default::default()); | 282 | 47.0k | } |
|
283 | | |
284 | 1.63M | pub fn push1_extra<T: BasicValue<'ctx>>(&mut self, value: T, info: ExtraInfo) { |
285 | 1.63M | self.stack.push((value.as_basic_value_enum(), info)); |
286 | 1.63M | } <wasmer_compiler_llvm::translator::state::State>::push1_extra::<inkwell::values::float_value::FloatValue> Line | Count | Source | 284 | 61.1k | pub fn push1_extra<T: BasicValue<'ctx>>(&mut self, value: T, info: ExtraInfo) { | 285 | 61.1k | self.stack.push((value.as_basic_value_enum(), info)); | 286 | 61.1k | } |
<wasmer_compiler_llvm::translator::state::State>::push1_extra::<inkwell::values::enums::BasicValueEnum> Line | Count | Source | 284 | 1.12M | pub fn push1_extra<T: BasicValue<'ctx>>(&mut self, value: T, info: ExtraInfo) { | 285 | 1.12M | self.stack.push((value.as_basic_value_enum(), info)); | 286 | 1.12M | } |
<wasmer_compiler_llvm::translator::state::State>::push1_extra::<inkwell::values::int_value::IntValue> Line | Count | Source | 284 | 448k | pub fn push1_extra<T: BasicValue<'ctx>>(&mut self, value: T, info: ExtraInfo) { | 285 | 448k | self.stack.push((value.as_basic_value_enum(), info)); | 286 | 448k | } |
|
287 | | |
288 | 327k | pub fn pop1(&mut self) -> Result<BasicValueEnum<'ctx>, CompileError> { |
289 | 327k | Ok(self.pop1_extra()?.0) |
290 | 327k | } |
291 | | |
292 | 1.05M | pub fn pop1_extra(&mut self) -> Result<(BasicValueEnum<'ctx>, ExtraInfo), CompileError> { |
293 | 1.05M | self.stack |
294 | 1.05M | .pop() |
295 | 1.05M | .ok_or_else(|| CompileError::Codegen("pop1_extra: invalid value stack".to_string())) |
296 | 1.05M | } |
297 | | |
298 | 8.67k | pub fn pop2(&mut self) -> Result<(BasicValueEnum<'ctx>, BasicValueEnum<'ctx>), CompileError> { |
299 | 8.67k | let v2 = self.pop1()?; |
300 | 8.67k | let v1 = self.pop1()?; |
301 | 8.67k | Ok((v1, v2)) |
302 | 8.67k | } |
303 | | |
304 | | #[allow(clippy::type_complexity)] |
305 | 92.6k | pub fn pop2_extra( |
306 | 92.6k | &mut self, |
307 | 92.6k | ) -> Result< |
308 | 92.6k | ( |
309 | 92.6k | (BasicValueEnum<'ctx>, ExtraInfo), |
310 | 92.6k | (BasicValueEnum<'ctx>, ExtraInfo), |
311 | 92.6k | ), |
312 | 92.6k | CompileError, |
313 | 92.6k | > { |
314 | 92.6k | let v2 = self.pop1_extra()?; |
315 | 92.6k | let v1 = self.pop1_extra()?; |
316 | 92.6k | Ok((v1, v2)) |
317 | 92.6k | } |
318 | | |
319 | 0 | pub fn pop3( |
320 | 0 | &mut self, |
321 | 0 | ) -> Result< |
322 | 0 | ( |
323 | 0 | BasicValueEnum<'ctx>, |
324 | 0 | BasicValueEnum<'ctx>, |
325 | 0 | BasicValueEnum<'ctx>, |
326 | 0 | ), |
327 | 0 | CompileError, |
328 | 0 | > { |
329 | 0 | let v3 = self.pop1()?; |
330 | 0 | let v2 = self.pop1()?; |
331 | 0 | let v1 = self.pop1()?; |
332 | 0 | Ok((v1, v2, v3)) |
333 | 0 | } |
334 | | |
335 | | #[allow(clippy::type_complexity)] |
336 | 895 | pub fn pop3_extra( |
337 | 895 | &mut self, |
338 | 895 | ) -> Result< |
339 | 895 | ( |
340 | 895 | (BasicValueEnum<'ctx>, ExtraInfo), |
341 | 895 | (BasicValueEnum<'ctx>, ExtraInfo), |
342 | 895 | (BasicValueEnum<'ctx>, ExtraInfo), |
343 | 895 | ), |
344 | 895 | CompileError, |
345 | 895 | > { |
346 | 895 | let v3 = self.pop1_extra()?; |
347 | 895 | let v2 = self.pop1_extra()?; |
348 | 895 | let v1 = self.pop1_extra()?; |
349 | 895 | Ok((v1, v2, v3)) |
350 | 895 | } |
351 | | |
352 | 22.6k | pub fn peek1_extra(&self) -> Result<(BasicValueEnum<'ctx>, ExtraInfo), CompileError> { |
353 | 22.6k | let index = |
354 | 22.6k | self.stack.len().checked_sub(1).ok_or_else(|| { |
355 | 0 | CompileError::Codegen("peek1_extra: invalid value stack".to_string()) |
356 | 22.6k | })?; |
357 | 22.6k | Ok(self.stack[index]) |
358 | 22.6k | } |
359 | | |
360 | 1.34k | pub fn peekn(&self, n: usize) -> Result<Vec<BasicValueEnum<'ctx>>, CompileError> { |
361 | 2.84k | Ok(self.peekn_extra(n)?.iter().map(|x| x.0).collect()) |
362 | 1.34k | } |
363 | | |
364 | 157k | pub fn peekn_extra( |
365 | 157k | &self, |
366 | 157k | n: usize, |
367 | 157k | ) -> Result<&[(BasicValueEnum<'ctx>, ExtraInfo)], CompileError> { |
368 | 157k | let index = |
369 | 157k | self.stack.len().checked_sub(n).ok_or_else(|| { |
370 | 0 | CompileError::Codegen("peekn_extra: invalid value stack".to_string()) |
371 | 157k | })?; |
372 | 157k | Ok(&self.stack[index..]) |
373 | 157k | } |
374 | | |
375 | 146k | pub fn popn_save_extra( |
376 | 146k | &mut self, |
377 | 146k | n: usize, |
378 | 146k | ) -> Result<Vec<(BasicValueEnum<'ctx>, ExtraInfo)>, CompileError> { |
379 | 146k | let v = self.peekn_extra(n)?.to_vec(); |
380 | 146k | self.popn(n)?; |
381 | 146k | Ok(v) |
382 | 146k | } |
383 | | |
384 | 154k | pub fn popn(&mut self, n: usize) -> Result<(), CompileError> { |
385 | 154k | let index = self |
386 | 154k | .stack |
387 | 154k | .len() |
388 | 154k | .checked_sub(n) |
389 | 154k | .ok_or_else(|| CompileError::Codegen("popn: invalid value stack".to_string()))?; |
390 | | |
391 | 154k | self.stack.truncate(index); |
392 | 154k | Ok(()) |
393 | 154k | } |
394 | | |
395 | 184k | pub fn push_block(&mut self, next: BasicBlock<'ctx>, phis: SmallVec<[PhiValue<'ctx>; 1]>) { |
396 | 184k | self.control_stack.push(ControlFrame::Block { |
397 | 184k | next, |
398 | 184k | phis, |
399 | 184k | stack_size_snapshot: self.stack.len(), |
400 | 184k | }); |
401 | 184k | } |
402 | | |
403 | 84.2k | pub fn push_loop( |
404 | 84.2k | &mut self, |
405 | 84.2k | body: BasicBlock<'ctx>, |
406 | 84.2k | next: BasicBlock<'ctx>, |
407 | 84.2k | loop_body_phis: SmallVec<[PhiValue<'ctx>; 1]>, |
408 | 84.2k | phis: SmallVec<[PhiValue<'ctx>; 1]>, |
409 | 84.2k | ) { |
410 | 84.2k | self.control_stack.push(ControlFrame::Loop { |
411 | 84.2k | body, |
412 | 84.2k | next, |
413 | 84.2k | loop_body_phis, |
414 | 84.2k | phis, |
415 | 84.2k | stack_size_snapshot: self.stack.len(), |
416 | 84.2k | }); |
417 | 84.2k | } |
418 | | |
419 | 6.21k | pub fn push_if( |
420 | 6.21k | &mut self, |
421 | 6.21k | if_then: BasicBlock<'ctx>, |
422 | 6.21k | if_else: BasicBlock<'ctx>, |
423 | 6.21k | next: BasicBlock<'ctx>, |
424 | 6.21k | then_phis: SmallVec<[PhiValue<'ctx>; 1]>, |
425 | 6.21k | else_phis: SmallVec<[PhiValue<'ctx>; 1]>, |
426 | 6.21k | next_phis: SmallVec<[PhiValue<'ctx>; 1]>, |
427 | 6.21k | ) { |
428 | 6.21k | self.control_stack.push(ControlFrame::IfElse { |
429 | 6.21k | if_then, |
430 | 6.21k | if_else, |
431 | 6.21k | next, |
432 | 6.21k | then_phis, |
433 | 6.21k | else_phis, |
434 | 6.21k | next_phis, |
435 | 6.21k | stack_size_snapshot: self.stack.len(), |
436 | 6.21k | if_else_state: IfElseState::If, |
437 | 6.21k | }); |
438 | 6.21k | } |
439 | | } |