Coverage Report

Created: 2024-10-16 07:58

/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
}