• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

henrythasler / rust-tiny-wasm / 27862377511

20 Jun 2026 06:05AM UTC coverage: 95.509% (-0.004%) from 95.513%
27862377511

push

github

henrythasler
implement f32.sub and f64.sub

Co-authored-by: Copilot <copilot@github.com>

22 of 23 new or added lines in 3 files covered. (95.65%)

1 existing line in 1 file now uncovered.

2084 of 2182 relevant lines covered (95.51%)

63.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.08
/src/compiler/function.rs
1
use crate::runtime::WasmReturnCode;
2

3
use super::*;
4

5
pub fn compile_function(
165✔
6
    reader: &mut wasmparser::OperatorsReader<'_>,
165✔
7
    func_type: &wasmparser::FuncType,
165✔
8
    locals: &[(u32, ValType)],
165✔
9
    machinecode: &mut Vec<u32>,
165✔
10
) -> Result<usize> {
165✔
11
    // Value stack starts empty
12
    let mut value_stack: Vec<StackElement> = vec![];
165✔
13

14
    // Control stack is initialized with the (implicit) outer func-block
15
    let mut control_stack: Vec<ControlFrame> = vec![ControlFrame {
165✔
16
        opcode: Opcode::Func,
165✔
17
        start_types: func_type.params().to_vec(),
165✔
18
        end_types: func_type.results().to_vec(),
165✔
19
        stack_height: value_stack.len(),
165✔
20
        value_stack: None,
165✔
21
        register_index: None,
165✔
22
        result_register: None,
165✔
23
        machinecode_offset: machinecode.len(),
165✔
24
        patches: vec![],
165✔
25
    }];
165✔
26

27
    let mut trap_locations: Vec<Patch> = vec![];
165✔
28

29
    let initial_size = machinecode.len();
165✔
30
    let mut register_pool = RegisterPool::new();
165✔
31

32
    // calculate initial stack size from all parameters and locals
33
    let (_variables_size, stack_size) = get_aligned_stack_size(func_type, locals);
165✔
34
    // println!("{} {:?}", _variables_size, stack_size);
35

36
    // every functions starts with an epilogue to save the initial state and create a new stack frame
37
    emit_prologue(stack_size, &mut register_pool, machinecode);
165✔
38

39
    let mut variables: Vec<LocalVar> = vec![];
165✔
40
    let mut stack_offset = 0;
165✔
41
    // save parameters to stack
42
    if !func_type.params().is_empty() {
165✔
43
        variables.extend(save_parameters_to_stack(
94✔
44
            &mut stack_offset,
94✔
45
            func_type.params(),
94✔
46
            machinecode,
94✔
47
        ));
94✔
48
    }
94✔
49

50
    if !locals.is_empty() {
165✔
51
        variables.extend(save_locals_to_stack(&mut stack_offset, locals, machinecode));
16✔
52
    }
149✔
53

54
    'expression: while !reader.eof() {
1,157✔
55
        let index = reader.original_position();
1,157✔
56
        let op = reader.read().unwrap();
1,157✔
57
        match op {
1,157✔
58
            Operator::Drop => compile_drop(&mut value_stack, &mut register_pool),
58✔
59
            Operator::Return => compile_return(&mut control_stack, &value_stack, machinecode),
24✔
60
            Operator::Block { blockty } => {
54✔
61
                compile_block(
54✔
62
                    blockty,
54✔
63
                    &mut control_stack,
54✔
64
                    &mut value_stack,
54✔
65
                    &mut register_pool,
54✔
66
                    machinecode,
54✔
67
                );
54✔
68
            }
54✔
69
            Operator::Br { relative_depth } => {
14✔
70
                compile_br(
14✔
71
                    relative_depth,
14✔
72
                    &mut control_stack,
14✔
73
                    &value_stack,
14✔
74
                    // &mut register_pool,
14✔
75
                    machinecode,
14✔
76
                );
14✔
77
            }
14✔
78
            Operator::BrIf { relative_depth } => {
54✔
79
                compile_brif(
54✔
80
                    relative_depth,
54✔
81
                    &mut control_stack,
54✔
82
                    &mut value_stack,
54✔
83
                    &mut register_pool,
54✔
84
                    machinecode,
54✔
85
                );
54✔
86
            }
54✔
87
            Operator::Loop { blockty } => {
8✔
88
                compile_loop(
8✔
89
                    blockty,
8✔
90
                    &mut control_stack,
8✔
91
                    &mut value_stack,
8✔
92
                    &mut register_pool,
8✔
93
                    machinecode,
8✔
94
                );
8✔
95
            }
8✔
96
            Operator::If { blockty } => {
20✔
97
                compile_if(
20✔
98
                    blockty,
20✔
99
                    &mut control_stack,
20✔
100
                    &mut value_stack,
20✔
101
                    &mut register_pool,
20✔
102
                    machinecode,
20✔
103
                );
20✔
104
            }
20✔
105
            Operator::Else => {
16✔
106
                compile_else(
16✔
107
                    &mut control_stack,
16✔
108
                    &mut value_stack,
16✔
109
                    &mut register_pool,
16✔
110
                    machinecode,
16✔
111
                );
16✔
112
            }
16✔
113
            Operator::End => {
114
                if compile_end(
246✔
115
                    &mut control_stack,
246✔
116
                    &mut value_stack,
246✔
117
                    &mut register_pool,
246✔
118
                    machinecode,
246✔
119
                ) {
120
                    break 'expression;
164✔
121
                }
82✔
122
            }
123
            Operator::I32LtS | Operator::I64LtS | Operator::I32LeU | Operator::I64LeU => {
124
                compile_relop(&op, &mut value_stack, &mut register_pool, machinecode)
32✔
125
            }
126
            Operator::I32Eqz | Operator::I64Eqz => {
127
                compile_testop(&op, &mut value_stack, machinecode)
2✔
128
            }
129
            Operator::I32Const { value } => {
176✔
130
                compile_const(
176✔
131
                    &op,
176✔
132
                    value,
176✔
133
                    &mut value_stack,
176✔
134
                    &mut register_pool,
176✔
135
                    machinecode,
176✔
136
                );
176✔
137
            }
176✔
138
            Operator::I64Const { value } => {
80✔
139
                compile_const(
80✔
140
                    &op,
80✔
141
                    value,
80✔
142
                    &mut value_stack,
80✔
143
                    &mut register_pool,
80✔
144
                    machinecode,
80✔
145
                );
80✔
146
            }
80✔
147
            Operator::F32Const { value } => {
2✔
148
                compile_float_const(
2✔
149
                    &op,
2✔
150
                    IeeeFloat::F32(value),
2✔
151
                    &mut value_stack,
2✔
152
                    &mut register_pool,
2✔
153
                    machinecode,
2✔
154
                );
2✔
155
            }
2✔
156
            Operator::F64Const { value } => {
2✔
157
                compile_float_const(
2✔
158
                    &op,
2✔
159
                    IeeeFloat::F64(value),
2✔
160
                    &mut value_stack,
2✔
161
                    &mut register_pool,
2✔
162
                    machinecode,
2✔
163
                );
2✔
164
            }
2✔
165
            Operator::LocalGet { local_index } => {
216✔
166
                let var = variables.get(local_index as usize).unwrap();
216✔
167
                compile_local_get(
216✔
168
                    var,
216✔
169
                    var.offset,
216✔
170
                    &mut value_stack,
216✔
171
                    &mut register_pool,
216✔
172
                    machinecode,
216✔
173
                );
216✔
174
            }
216✔
175
            Operator::LocalSet { local_index } => {
56✔
176
                let var = variables.get(local_index as usize).unwrap();
56✔
177
                compile_local_set(
56✔
178
                    var,
56✔
179
                    var.offset,
56✔
180
                    &mut value_stack,
56✔
181
                    &mut register_pool,
56✔
182
                    machinecode,
56✔
183
                );
56✔
184
            }
56✔
185
            Operator::LocalTee { local_index } => {
6✔
186
                let var = variables.get(local_index as usize).unwrap();
6✔
187
                compile_local_tee(var, var.offset, &mut value_stack, machinecode);
6✔
188
            }
6✔
189
            Operator::I32Add
190
            | Operator::I64Add
191
            | Operator::I32Sub
192
            | Operator::I64Sub
193
            | Operator::I32Mul
194
            | Operator::I64Mul
195
            | Operator::I32DivU
196
            | Operator::I64DivU
197
            | Operator::I32DivS
198
            | Operator::I64DivS
199
            | Operator::F32Add
200
            | Operator::F64Add
201
            | Operator::F32Sub
202
            | Operator::F64Sub => {
82✔
203
                compile_binop(
82✔
204
                    &op,
82✔
205
                    &mut value_stack,
82✔
206
                    &mut register_pool,
82✔
207
                    &mut trap_locations,
82✔
208
                    machinecode,
82✔
209
                );
82✔
210
            }
82✔
211
            Operator::I32Ctz | Operator::I64Ctz => {
8✔
212
                compile_unop(&op, &mut value_stack, machinecode);
8✔
213
            }
8✔
214
            _ => {
215
                return Err(TinyWasmError::Compiler(format!(
1✔
216
                    "unsupported instruction: {:?} at position {}",
1✔
217
                    op, index
1✔
218
                )));
1✔
219
            }
220
        }
221
    }
222

223
    // move result values to result registers according to Aarch64 Procedure Call Standard (X0..X7)
224
    // X0: Return Code (0=Ok, 1=Trap),
225
    // X1: Result or Trap code
226
    if func_type.results().is_empty() {
164✔
227
        // Return Code =Ok (0)
12✔
228
        machinecode.push(processing::mov_imm(
12✔
229
            IReg::X0,
12✔
230
            WasmReturnCode::Ok as u32,
12✔
231
            RegSize::Int64bit,
12✔
232
        ));
12✔
233
        // Result=0
12✔
234
        machinecode.push(processing::mov_reg(IReg::X1, IReg::XZR, RegSize::Int64bit));
12✔
235
    } else {
12✔
236
        load_results(&mut value_stack, func_type.results().len(), machinecode)?;
152✔
237
    }
238

239
    for patch in trap_locations {
164✔
240
        match patch.instruction {
28✔
241
            Instruction::Br => {
28✔
242
                let offset = (machinecode.len() - patch.location) as i32 * 4;
28✔
243
                let location = machinecode
28✔
244
                    .get_mut(patch.location)
28✔
245
                    .expect("patch location should point to valid location");
28✔
246
                branch::patch_branch(offset, location);
28✔
247
            }
28✔
248
            _ => panic!("unexpected instruction"),
×
249
        }
250
    }
251

252
    // restore initial state before returning to the caller
253
    emit_epilogue(stack_size, machinecode);
164✔
254

255
    // add padding to INSTRUCTION_SIZE to align subsequent functions to the correct size
256
    let padding_instructions =
164✔
257
        ((machinecode.len() * INSTRUCTION_SIZE) % mem::align_of::<fn()>()) / INSTRUCTION_SIZE;
164✔
258
    for _ in 0..padding_instructions {
164✔
259
        machinecode.push(hint::nop());
118✔
260
    }
118✔
261

262
    Ok(machinecode.len() - initial_size)
164✔
263
}
165✔
264

265
pub fn map_op_to_valtype(op: &Operator) -> ValType {
384✔
266
    match op {
384✔
267
        Operator::I32Add
268
        | Operator::I32Sub
269
        | Operator::I32Mul
270
        | Operator::I32Const { .. }
271
        | Operator::I32Ctz
272
        | Operator::I32LtS
273
        | Operator::I32LeU
274
        | Operator::I32Eqz
275
        | Operator::I32DivS
276
        | Operator::I32DivU => ValType::I32,
242✔
277
        Operator::I64Add
278
        | Operator::I64Sub
279
        | Operator::I64Mul
280
        | Operator::I64Const { .. }
281
        | Operator::I64Ctz
282
        | Operator::I64LtS
283
        | Operator::I64LeU
284
        | Operator::I64Eqz
285
        | Operator::I64DivS
286
        | Operator::I64DivU => ValType::I64,
130✔
287
        Operator::F32Const { .. } => ValType::F32,
2✔
288
        Operator::F64Const { .. } => ValType::F64,
2✔
289
        Operator::F32Add | Operator::F32Sub => ValType::F32,
4✔
290
        Operator::F64Add | Operator::F64Sub => ValType::F64,
4✔
UNCOV
291
        _ => panic!("Operator '{:?}' not supported", op),
×
292
    }
293
}
384✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc