Skip to main content

ab_riscv_interpreter/v/zve64x/
widen_narrow.rs

1//! Zve64x widening, narrowing, and extension instructions
2
3#[cfg(test)]
4mod tests;
5pub mod zve64x_widen_narrow_helpers;
6
7use crate::v::vector_registers::VectorRegistersExt;
8use crate::v::zve64x::zve64x_helpers;
9use crate::{ExecutableInstruction, ExecutionError, ProgramCounter, RegisterFile, VirtualMemory};
10use ab_riscv_macros::instruction_execution;
11use ab_riscv_primitives::prelude::*;
12use core::fmt;
13use core::ops::ControlFlow;
14
15#[instruction_execution]
16impl<Reg, Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
17    ExecutableInstruction<Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
18    for Zve64xWidenNarrowInstruction<Reg>
19where
20    Reg: Register,
21    Regs: RegisterFile<Reg>,
22    ExtState: VectorRegistersExt<Reg, CustomError>,
23    [(); ExtState::ELEN as usize]:,
24    [(); ExtState::VLEN as usize]:,
25    [(); ExtState::VLENB as usize]:,
26    Memory: VirtualMemory,
27    PC: ProgramCounter<Reg::Type, Memory, CustomError>,
28    CustomError: fmt::Debug,
29{
30    #[inline(always)]
31    fn execute(
32        self,
33        regs: &mut Regs,
34        ext_state: &mut ExtState,
35        _memory: &mut Memory,
36        program_counter: &mut PC,
37        _system_instruction_handler: &mut InstructionHandler,
38    ) -> Result<ControlFlow<()>, ExecutionError<Reg::Type, CustomError>> {
39        match self {
40            // vwaddu.vv - 2*SEW = zext(SEW) + zext(SEW)
41            Self::VwadduVv { vd, vs2, vs1, vm } => {
42                if !ext_state.vector_instructions_allowed() {
43                    Err(ExecutionError::IllegalInstruction {
44                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
45                    })?;
46                }
47                let vtype = ext_state
48                    .vtype()
49                    .ok_or(ExecutionError::IllegalInstruction {
50                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
51                    })?;
52                let sew = vtype.vsew();
53                // Widening requires SEW < 64; 2*SEW must fit in ELEN=64
54                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
55                    Err(ExecutionError::IllegalInstruction {
56                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
57                    })?;
58                }
59                let group_regs = vtype.vlmul().register_count();
60                let wide_eew = match sew {
61                    Vsew::E8 => Eew::E16,
62                    Vsew::E16 => Eew::E32,
63                    Vsew::E32 => Eew::E64,
64                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
65                };
66                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
67                    ExecutionError::IllegalInstruction {
68                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
69                    },
70                )?;
71                zve64x_widen_narrow_helpers::check_vd_widen_alignment::<Reg, _, _, _>(
72                    program_counter,
73                    vd,
74                    vs2,
75                    Some(vs1),
76                    group_regs,
77                    wide_group_regs,
78                )?;
79                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
80                    program_counter,
81                    vs2,
82                    group_regs,
83                )?;
84                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
85                    program_counter,
86                    vs1,
87                    group_regs,
88                )?;
89                if !vm && vd.bits() == 0 {
90                    Err(ExecutionError::IllegalInstruction {
91                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
92                    })?;
93                }
94                let vl = ext_state.vl();
95                let vstart = u32::from(ext_state.vstart());
96                // SAFETY: alignment/overlap/SEW checked above
97                unsafe {
98                    zve64x_widen_narrow_helpers::execute_widen_op(
99                        ext_state,
100                        vd,
101                        vs2,
102                        zve64x_widen_narrow_helpers::OpSrc::Vreg(vs1.bits()),
103                        vm,
104                        vl,
105                        vstart,
106                        sew,
107                        true,
108                        true,
109                        |a, b| a.wrapping_add(b),
110                    );
111                }
112            }
113            // vwaddu.vx - 2*SEW = zext(SEW) + zext(xlen->SEW)
114            Self::VwadduVx { vd, vs2, rs1, vm } => {
115                if !ext_state.vector_instructions_allowed() {
116                    Err(ExecutionError::IllegalInstruction {
117                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
118                    })?;
119                }
120                let vtype = ext_state
121                    .vtype()
122                    .ok_or(ExecutionError::IllegalInstruction {
123                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
124                    })?;
125                let sew = vtype.vsew();
126                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
127                    Err(ExecutionError::IllegalInstruction {
128                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
129                    })?;
130                }
131                let group_regs = vtype.vlmul().register_count();
132                let wide_eew = match sew {
133                    Vsew::E8 => Eew::E16,
134                    Vsew::E16 => Eew::E32,
135                    Vsew::E32 => Eew::E64,
136                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
137                };
138                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
139                    ExecutionError::IllegalInstruction {
140                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
141                    },
142                )?;
143                zve64x_widen_narrow_helpers::check_vd_widen_alignment::<Reg, _, _, _>(
144                    program_counter,
145                    vd,
146                    vs2,
147                    None,
148                    group_regs,
149                    wide_group_regs,
150                )?;
151                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
152                    program_counter,
153                    vs2,
154                    group_regs,
155                )?;
156                if !vm && vd.bits() == 0 {
157                    Err(ExecutionError::IllegalInstruction {
158                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
159                    })?;
160                }
161                let vl = ext_state.vl();
162                let vstart = u32::from(ext_state.vstart());
163                // Scalar is zero-extended to 2*SEW; the low SEW bits are what matter
164                let scalar = regs.read(rs1).as_u64();
165                // SAFETY: alignment/overlap/SEW checked above
166                unsafe {
167                    zve64x_widen_narrow_helpers::execute_widen_op(
168                        ext_state,
169                        vd,
170                        vs2,
171                        zve64x_widen_narrow_helpers::OpSrc::Scalar(scalar),
172                        vm,
173                        vl,
174                        vstart,
175                        sew,
176                        true,
177                        true,
178                        |a, b| a.wrapping_add(b),
179                    );
180                }
181            }
182            // vwadd.vv - 2*SEW = sext(SEW) + sext(SEW)
183            Self::VwaddVv { vd, vs2, vs1, vm } => {
184                if !ext_state.vector_instructions_allowed() {
185                    Err(ExecutionError::IllegalInstruction {
186                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
187                    })?;
188                }
189                let vtype = ext_state
190                    .vtype()
191                    .ok_or(ExecutionError::IllegalInstruction {
192                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
193                    })?;
194                let sew = vtype.vsew();
195                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
196                    Err(ExecutionError::IllegalInstruction {
197                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
198                    })?;
199                }
200                let group_regs = vtype.vlmul().register_count();
201                let wide_eew = match sew {
202                    Vsew::E8 => Eew::E16,
203                    Vsew::E16 => Eew::E32,
204                    Vsew::E32 => Eew::E64,
205                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
206                };
207                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
208                    ExecutionError::IllegalInstruction {
209                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
210                    },
211                )?;
212                zve64x_widen_narrow_helpers::check_vd_widen_alignment::<Reg, _, _, _>(
213                    program_counter,
214                    vd,
215                    vs2,
216                    Some(vs1),
217                    group_regs,
218                    wide_group_regs,
219                )?;
220                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
221                    program_counter,
222                    vs2,
223                    group_regs,
224                )?;
225                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
226                    program_counter,
227                    vs1,
228                    group_regs,
229                )?;
230                if !vm && vd.bits() == 0 {
231                    Err(ExecutionError::IllegalInstruction {
232                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
233                    })?;
234                }
235                let vl = ext_state.vl();
236                let vstart = u32::from(ext_state.vstart());
237                // SAFETY: alignment/overlap/SEW checked above
238                unsafe {
239                    zve64x_widen_narrow_helpers::execute_widen_op(
240                        ext_state,
241                        vd,
242                        vs2,
243                        zve64x_widen_narrow_helpers::OpSrc::Vreg(vs1.bits()),
244                        vm,
245                        vl,
246                        vstart,
247                        sew,
248                        false,
249                        false,
250                        |a, b| a.wrapping_add(b),
251                    );
252                }
253            }
254            // vwadd.vx - 2*SEW = sext(SEW) + sext(rs1)
255            Self::VwaddVx { vd, vs2, rs1, vm } => {
256                if !ext_state.vector_instructions_allowed() {
257                    Err(ExecutionError::IllegalInstruction {
258                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
259                    })?;
260                }
261                let vtype = ext_state
262                    .vtype()
263                    .ok_or(ExecutionError::IllegalInstruction {
264                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
265                    })?;
266                let sew = vtype.vsew();
267                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
268                    Err(ExecutionError::IllegalInstruction {
269                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
270                    })?;
271                }
272                let group_regs = vtype.vlmul().register_count();
273                let wide_eew = match sew {
274                    Vsew::E8 => Eew::E16,
275                    Vsew::E16 => Eew::E32,
276                    Vsew::E32 => Eew::E64,
277                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
278                };
279                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
280                    ExecutionError::IllegalInstruction {
281                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
282                    },
283                )?;
284                zve64x_widen_narrow_helpers::check_vd_widen_alignment::<Reg, _, _, _>(
285                    program_counter,
286                    vd,
287                    vs2,
288                    None,
289                    group_regs,
290                    wide_group_regs,
291                )?;
292                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
293                    program_counter,
294                    vs2,
295                    group_regs,
296                )?;
297                if !vm && vd.bits() == 0 {
298                    Err(ExecutionError::IllegalInstruction {
299                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
300                    })?;
301                }
302                let vl = ext_state.vl();
303                let vstart = u32::from(ext_state.vstart());
304                // Scalar is sign-extended from XLEN to 64 bits
305                let scalar = zve64x_widen_narrow_helpers::sign_extend_bits(
306                    regs.read(rs1).as_u64(),
307                    u32::from(Reg::XLEN),
308                )
309                .cast_unsigned();
310                // SAFETY: alignment/overlap/SEW checked above
311                unsafe {
312                    zve64x_widen_narrow_helpers::execute_widen_op(
313                        ext_state,
314                        vd,
315                        vs2,
316                        zve64x_widen_narrow_helpers::OpSrc::Scalar(scalar),
317                        vm,
318                        vl,
319                        vstart,
320                        sew,
321                        false,
322                        false,
323                        |a, b| a.wrapping_add(b),
324                    );
325                }
326            }
327            // vwsubu.vv - 2*SEW = zext(SEW) - zext(SEW)
328            Self::VwsubuVv { vd, vs2, vs1, vm } => {
329                if !ext_state.vector_instructions_allowed() {
330                    Err(ExecutionError::IllegalInstruction {
331                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
332                    })?;
333                }
334                let vtype = ext_state
335                    .vtype()
336                    .ok_or(ExecutionError::IllegalInstruction {
337                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
338                    })?;
339                let sew = vtype.vsew();
340                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
341                    Err(ExecutionError::IllegalInstruction {
342                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
343                    })?;
344                }
345                let group_regs = vtype.vlmul().register_count();
346                let wide_eew = match sew {
347                    Vsew::E8 => Eew::E16,
348                    Vsew::E16 => Eew::E32,
349                    Vsew::E32 => Eew::E64,
350                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
351                };
352                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
353                    ExecutionError::IllegalInstruction {
354                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
355                    },
356                )?;
357                zve64x_widen_narrow_helpers::check_vd_widen_alignment::<Reg, _, _, _>(
358                    program_counter,
359                    vd,
360                    vs2,
361                    Some(vs1),
362                    group_regs,
363                    wide_group_regs,
364                )?;
365                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
366                    program_counter,
367                    vs2,
368                    group_regs,
369                )?;
370                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
371                    program_counter,
372                    vs1,
373                    group_regs,
374                )?;
375                if !vm && vd.bits() == 0 {
376                    Err(ExecutionError::IllegalInstruction {
377                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
378                    })?;
379                }
380                let vl = ext_state.vl();
381                let vstart = u32::from(ext_state.vstart());
382                // SAFETY: alignment/overlap/SEW checked above
383                unsafe {
384                    zve64x_widen_narrow_helpers::execute_widen_op(
385                        ext_state,
386                        vd,
387                        vs2,
388                        zve64x_widen_narrow_helpers::OpSrc::Vreg(vs1.bits()),
389                        vm,
390                        vl,
391                        vstart,
392                        sew,
393                        true,
394                        true,
395                        |a, b| a.wrapping_sub(b),
396                    );
397                }
398            }
399            // vwsubu.vx - 2*SEW = zext(SEW) - zext(rs1)
400            Self::VwsubuVx { vd, vs2, rs1, vm } => {
401                if !ext_state.vector_instructions_allowed() {
402                    Err(ExecutionError::IllegalInstruction {
403                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
404                    })?;
405                }
406                let vtype = ext_state
407                    .vtype()
408                    .ok_or(ExecutionError::IllegalInstruction {
409                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
410                    })?;
411                let sew = vtype.vsew();
412                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
413                    Err(ExecutionError::IllegalInstruction {
414                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
415                    })?;
416                }
417                let group_regs = vtype.vlmul().register_count();
418                let wide_eew = match sew {
419                    Vsew::E8 => Eew::E16,
420                    Vsew::E16 => Eew::E32,
421                    Vsew::E32 => Eew::E64,
422                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
423                };
424                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
425                    ExecutionError::IllegalInstruction {
426                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
427                    },
428                )?;
429                zve64x_widen_narrow_helpers::check_vd_widen_alignment::<Reg, _, _, _>(
430                    program_counter,
431                    vd,
432                    vs2,
433                    None,
434                    group_regs,
435                    wide_group_regs,
436                )?;
437                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
438                    program_counter,
439                    vs2,
440                    group_regs,
441                )?;
442                if !vm && vd.bits() == 0 {
443                    Err(ExecutionError::IllegalInstruction {
444                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
445                    })?;
446                }
447                let vl = ext_state.vl();
448                let vstart = u32::from(ext_state.vstart());
449                let scalar = regs.read(rs1).as_u64();
450                // SAFETY: alignment/overlap/SEW checked above
451                unsafe {
452                    zve64x_widen_narrow_helpers::execute_widen_op(
453                        ext_state,
454                        vd,
455                        vs2,
456                        zve64x_widen_narrow_helpers::OpSrc::Scalar(scalar),
457                        vm,
458                        vl,
459                        vstart,
460                        sew,
461                        true,
462                        true,
463                        |a, b| a.wrapping_sub(b),
464                    );
465                }
466            }
467            // vwsub.vv - 2*SEW = sext(SEW) - sext(SEW)
468            Self::VwsubVv { vd, vs2, vs1, vm } => {
469                if !ext_state.vector_instructions_allowed() {
470                    Err(ExecutionError::IllegalInstruction {
471                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
472                    })?;
473                }
474                let vtype = ext_state
475                    .vtype()
476                    .ok_or(ExecutionError::IllegalInstruction {
477                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
478                    })?;
479                let sew = vtype.vsew();
480                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
481                    Err(ExecutionError::IllegalInstruction {
482                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
483                    })?;
484                }
485                let group_regs = vtype.vlmul().register_count();
486                let wide_eew = match sew {
487                    Vsew::E8 => Eew::E16,
488                    Vsew::E16 => Eew::E32,
489                    Vsew::E32 => Eew::E64,
490                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
491                };
492                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
493                    ExecutionError::IllegalInstruction {
494                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
495                    },
496                )?;
497                zve64x_widen_narrow_helpers::check_vd_widen_alignment::<Reg, _, _, _>(
498                    program_counter,
499                    vd,
500                    vs2,
501                    Some(vs1),
502                    group_regs,
503                    wide_group_regs,
504                )?;
505                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
506                    program_counter,
507                    vs2,
508                    group_regs,
509                )?;
510                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
511                    program_counter,
512                    vs1,
513                    group_regs,
514                )?;
515                if !vm && vd.bits() == 0 {
516                    Err(ExecutionError::IllegalInstruction {
517                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
518                    })?;
519                }
520                let vl = ext_state.vl();
521                let vstart = u32::from(ext_state.vstart());
522                // SAFETY: alignment/overlap/SEW checked above
523                unsafe {
524                    zve64x_widen_narrow_helpers::execute_widen_op(
525                        ext_state,
526                        vd,
527                        vs2,
528                        zve64x_widen_narrow_helpers::OpSrc::Vreg(vs1.bits()),
529                        vm,
530                        vl,
531                        vstart,
532                        sew,
533                        false,
534                        false,
535                        |a, b| a.wrapping_sub(b),
536                    );
537                }
538            }
539            // vwsub.vx - 2*SEW = sext(SEW) - sext(rs1)
540            Self::VwsubVx { vd, vs2, rs1, vm } => {
541                if !ext_state.vector_instructions_allowed() {
542                    Err(ExecutionError::IllegalInstruction {
543                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
544                    })?;
545                }
546                let vtype = ext_state
547                    .vtype()
548                    .ok_or(ExecutionError::IllegalInstruction {
549                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
550                    })?;
551                let sew = vtype.vsew();
552                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
553                    Err(ExecutionError::IllegalInstruction {
554                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
555                    })?;
556                }
557                let group_regs = vtype.vlmul().register_count();
558                let wide_eew = match sew {
559                    Vsew::E8 => Eew::E16,
560                    Vsew::E16 => Eew::E32,
561                    Vsew::E32 => Eew::E64,
562                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
563                };
564                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
565                    ExecutionError::IllegalInstruction {
566                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
567                    },
568                )?;
569                zve64x_widen_narrow_helpers::check_vd_widen_alignment::<Reg, _, _, _>(
570                    program_counter,
571                    vd,
572                    vs2,
573                    None,
574                    group_regs,
575                    wide_group_regs,
576                )?;
577                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
578                    program_counter,
579                    vs2,
580                    group_regs,
581                )?;
582                if !vm && vd.bits() == 0 {
583                    Err(ExecutionError::IllegalInstruction {
584                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
585                    })?;
586                }
587                let vl = ext_state.vl();
588                let vstart = u32::from(ext_state.vstart());
589                let scalar = zve64x_widen_narrow_helpers::sign_extend_bits(
590                    regs.read(rs1).as_u64(),
591                    u32::from(Reg::XLEN),
592                )
593                .cast_unsigned();
594                // SAFETY: alignment/overlap/SEW checked above
595                unsafe {
596                    zve64x_widen_narrow_helpers::execute_widen_op(
597                        ext_state,
598                        vd,
599                        vs2,
600                        zve64x_widen_narrow_helpers::OpSrc::Scalar(scalar),
601                        vm,
602                        vl,
603                        vstart,
604                        sew,
605                        false,
606                        false,
607                        |a, b| a.wrapping_sub(b),
608                    );
609                }
610            }
611            // vwaddu.wv - 2*SEW = 2*SEW + zext(SEW)
612            Self::VwadduWv { vd, vs2, vs1, vm } => {
613                if !ext_state.vector_instructions_allowed() {
614                    Err(ExecutionError::IllegalInstruction {
615                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
616                    })?;
617                }
618                let vtype = ext_state
619                    .vtype()
620                    .ok_or(ExecutionError::IllegalInstruction {
621                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
622                    })?;
623                let sew = vtype.vsew();
624                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
625                    Err(ExecutionError::IllegalInstruction {
626                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
627                    })?;
628                }
629                let group_regs = vtype.vlmul().register_count();
630                let wide_eew = match sew {
631                    Vsew::E8 => Eew::E16,
632                    Vsew::E16 => Eew::E32,
633                    Vsew::E32 => Eew::E64,
634                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
635                };
636                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
637                    ExecutionError::IllegalInstruction {
638                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
639                    },
640                )?;
641                // vs2 is the wide source; vs1 is narrow
642                zve64x_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _, _>(
643                    program_counter,
644                    vs2,
645                    wide_group_regs,
646                )?;
647                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
648                    program_counter,
649                    vs1,
650                    group_regs,
651                )?;
652                zve64x_widen_narrow_helpers::check_vd_widen_alignment::<Reg, _, _, _>(
653                    program_counter,
654                    vd,
655                    vs1,
656                    None,
657                    group_regs,
658                    wide_group_regs,
659                )?;
660                if !vm && vd.bits() == 0 {
661                    Err(ExecutionError::IllegalInstruction {
662                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
663                    })?;
664                }
665                let vl = ext_state.vl();
666                let vstart = u32::from(ext_state.vstart());
667                // SAFETY: alignment/overlap/SEW checked above
668                unsafe {
669                    zve64x_widen_narrow_helpers::execute_widen_w_op(
670                        ext_state,
671                        vd,
672                        vs2,
673                        zve64x_widen_narrow_helpers::OpSrc::Vreg(vs1.bits()),
674                        vm,
675                        vl,
676                        vstart,
677                        sew,
678                        true,
679                        |a, b| a.wrapping_add(b),
680                    );
681                }
682            }
683            // vwaddu.wx - 2*SEW = 2*SEW + zext(rs1)
684            Self::VwadduWx { vd, vs2, rs1, vm } => {
685                if !ext_state.vector_instructions_allowed() {
686                    Err(ExecutionError::IllegalInstruction {
687                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
688                    })?;
689                }
690                let vtype = ext_state
691                    .vtype()
692                    .ok_or(ExecutionError::IllegalInstruction {
693                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
694                    })?;
695                let sew = vtype.vsew();
696                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
697                    Err(ExecutionError::IllegalInstruction {
698                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
699                    })?;
700                }
701                let wide_eew = match sew {
702                    Vsew::E8 => Eew::E16,
703                    Vsew::E16 => Eew::E32,
704                    Vsew::E32 => Eew::E64,
705                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
706                };
707                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
708                    ExecutionError::IllegalInstruction {
709                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
710                    },
711                )?;
712                // For .wx scalar variants vd may alias vs2 (same wide group); no narrow vs1
713                zve64x_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _, _>(
714                    program_counter,
715                    vs2,
716                    wide_group_regs,
717                )?;
718                zve64x_widen_narrow_helpers::check_vd_widen_no_src_check::<Reg, _, _, _>(
719                    program_counter,
720                    vd,
721                    wide_group_regs,
722                )?;
723                if !vm && vd.bits() == 0 {
724                    Err(ExecutionError::IllegalInstruction {
725                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
726                    })?;
727                }
728                let vl = ext_state.vl();
729                let vstart = u32::from(ext_state.vstart());
730                let scalar = regs.read(rs1).as_u64();
731                // SAFETY: alignment/overlap/SEW checked above
732                unsafe {
733                    zve64x_widen_narrow_helpers::execute_widen_w_op(
734                        ext_state,
735                        vd,
736                        vs2,
737                        zve64x_widen_narrow_helpers::OpSrc::Scalar(scalar),
738                        vm,
739                        vl,
740                        vstart,
741                        sew,
742                        true,
743                        |a, b| a.wrapping_add(b),
744                    );
745                }
746            }
747            // vwadd.wv - 2*SEW = 2*SEW + sext(SEW)
748            Self::VwaddWv { vd, vs2, vs1, vm } => {
749                if !ext_state.vector_instructions_allowed() {
750                    Err(ExecutionError::IllegalInstruction {
751                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
752                    })?;
753                }
754                let vtype = ext_state
755                    .vtype()
756                    .ok_or(ExecutionError::IllegalInstruction {
757                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
758                    })?;
759                let sew = vtype.vsew();
760                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
761                    Err(ExecutionError::IllegalInstruction {
762                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
763                    })?;
764                }
765                let group_regs = vtype.vlmul().register_count();
766                let wide_eew = match sew {
767                    Vsew::E8 => Eew::E16,
768                    Vsew::E16 => Eew::E32,
769                    Vsew::E32 => Eew::E64,
770                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
771                };
772                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
773                    ExecutionError::IllegalInstruction {
774                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
775                    },
776                )?;
777                zve64x_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _, _>(
778                    program_counter,
779                    vs2,
780                    wide_group_regs,
781                )?;
782                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
783                    program_counter,
784                    vs1,
785                    group_regs,
786                )?;
787                zve64x_widen_narrow_helpers::check_vd_widen_alignment::<Reg, _, _, _>(
788                    program_counter,
789                    vd,
790                    vs1,
791                    None,
792                    group_regs,
793                    wide_group_regs,
794                )?;
795                if !vm && vd.bits() == 0 {
796                    Err(ExecutionError::IllegalInstruction {
797                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
798                    })?;
799                }
800                let vl = ext_state.vl();
801                let vstart = u32::from(ext_state.vstart());
802                // SAFETY: alignment/overlap/SEW checked above
803                unsafe {
804                    zve64x_widen_narrow_helpers::execute_widen_w_op(
805                        ext_state,
806                        vd,
807                        vs2,
808                        zve64x_widen_narrow_helpers::OpSrc::Vreg(vs1.bits()),
809                        vm,
810                        vl,
811                        vstart,
812                        sew,
813                        false,
814                        |a, b| a.wrapping_add(b),
815                    );
816                }
817            }
818            // vwadd.wx - 2*SEW = 2*SEW + sext(rs1)
819            Self::VwaddWx { vd, vs2, rs1, vm } => {
820                if !ext_state.vector_instructions_allowed() {
821                    Err(ExecutionError::IllegalInstruction {
822                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
823                    })?;
824                }
825                let vtype = ext_state
826                    .vtype()
827                    .ok_or(ExecutionError::IllegalInstruction {
828                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
829                    })?;
830                let sew = vtype.vsew();
831                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
832                    Err(ExecutionError::IllegalInstruction {
833                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
834                    })?;
835                }
836                let wide_eew = match sew {
837                    Vsew::E8 => Eew::E16,
838                    Vsew::E16 => Eew::E32,
839                    Vsew::E32 => Eew::E64,
840                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
841                };
842                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
843                    ExecutionError::IllegalInstruction {
844                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
845                    },
846                )?;
847                zve64x_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _, _>(
848                    program_counter,
849                    vs2,
850                    wide_group_regs,
851                )?;
852                zve64x_widen_narrow_helpers::check_vd_widen_no_src_check::<Reg, _, _, _>(
853                    program_counter,
854                    vd,
855                    wide_group_regs,
856                )?;
857                if !vm && vd.bits() == 0 {
858                    Err(ExecutionError::IllegalInstruction {
859                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
860                    })?;
861                }
862                let vl = ext_state.vl();
863                let vstart = u32::from(ext_state.vstart());
864                let scalar = zve64x_widen_narrow_helpers::sign_extend_bits(
865                    regs.read(rs1).as_u64(),
866                    u32::from(Reg::XLEN),
867                )
868                .cast_unsigned();
869                // SAFETY: alignment/overlap/SEW checked above
870                unsafe {
871                    zve64x_widen_narrow_helpers::execute_widen_w_op(
872                        ext_state,
873                        vd,
874                        vs2,
875                        zve64x_widen_narrow_helpers::OpSrc::Scalar(scalar),
876                        vm,
877                        vl,
878                        vstart,
879                        sew,
880                        false,
881                        |a, b| a.wrapping_add(b),
882                    );
883                }
884            }
885            // vwsubu.wv - 2*SEW = 2*SEW - zext(SEW)
886            Self::VwsubuWv { vd, vs2, vs1, vm } => {
887                if !ext_state.vector_instructions_allowed() {
888                    Err(ExecutionError::IllegalInstruction {
889                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
890                    })?;
891                }
892                let vtype = ext_state
893                    .vtype()
894                    .ok_or(ExecutionError::IllegalInstruction {
895                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
896                    })?;
897                let sew = vtype.vsew();
898                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
899                    Err(ExecutionError::IllegalInstruction {
900                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
901                    })?;
902                }
903                let group_regs = vtype.vlmul().register_count();
904                let wide_eew = match sew {
905                    Vsew::E8 => Eew::E16,
906                    Vsew::E16 => Eew::E32,
907                    Vsew::E32 => Eew::E64,
908                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
909                };
910                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
911                    ExecutionError::IllegalInstruction {
912                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
913                    },
914                )?;
915                zve64x_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _, _>(
916                    program_counter,
917                    vs2,
918                    wide_group_regs,
919                )?;
920                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
921                    program_counter,
922                    vs1,
923                    group_regs,
924                )?;
925                zve64x_widen_narrow_helpers::check_vd_widen_alignment::<Reg, _, _, _>(
926                    program_counter,
927                    vd,
928                    vs1,
929                    None,
930                    group_regs,
931                    wide_group_regs,
932                )?;
933                if !vm && vd.bits() == 0 {
934                    Err(ExecutionError::IllegalInstruction {
935                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
936                    })?;
937                }
938                let vl = ext_state.vl();
939                let vstart = u32::from(ext_state.vstart());
940                // SAFETY: alignment/overlap/SEW checked above
941                unsafe {
942                    zve64x_widen_narrow_helpers::execute_widen_w_op(
943                        ext_state,
944                        vd,
945                        vs2,
946                        zve64x_widen_narrow_helpers::OpSrc::Vreg(vs1.bits()),
947                        vm,
948                        vl,
949                        vstart,
950                        sew,
951                        true,
952                        |a, b| a.wrapping_sub(b),
953                    );
954                }
955            }
956            // vwsubu.wx - 2*SEW = 2*SEW - zext(rs1)
957            Self::VwsubuWx { vd, vs2, rs1, vm } => {
958                if !ext_state.vector_instructions_allowed() {
959                    Err(ExecutionError::IllegalInstruction {
960                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
961                    })?;
962                }
963                let vtype = ext_state
964                    .vtype()
965                    .ok_or(ExecutionError::IllegalInstruction {
966                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
967                    })?;
968                let sew = vtype.vsew();
969                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
970                    Err(ExecutionError::IllegalInstruction {
971                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
972                    })?;
973                }
974                let wide_eew = match sew {
975                    Vsew::E8 => Eew::E16,
976                    Vsew::E16 => Eew::E32,
977                    Vsew::E32 => Eew::E64,
978                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
979                };
980                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
981                    ExecutionError::IllegalInstruction {
982                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
983                    },
984                )?;
985                zve64x_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _, _>(
986                    program_counter,
987                    vs2,
988                    wide_group_regs,
989                )?;
990                zve64x_widen_narrow_helpers::check_vd_widen_no_src_check::<Reg, _, _, _>(
991                    program_counter,
992                    vd,
993                    wide_group_regs,
994                )?;
995                if !vm && vd.bits() == 0 {
996                    Err(ExecutionError::IllegalInstruction {
997                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
998                    })?;
999                }
1000                let vl = ext_state.vl();
1001                let vstart = u32::from(ext_state.vstart());
1002                let scalar = regs.read(rs1).as_u64();
1003                // SAFETY: alignment/overlap/SEW checked above
1004                unsafe {
1005                    zve64x_widen_narrow_helpers::execute_widen_w_op(
1006                        ext_state,
1007                        vd,
1008                        vs2,
1009                        zve64x_widen_narrow_helpers::OpSrc::Scalar(scalar),
1010                        vm,
1011                        vl,
1012                        vstart,
1013                        sew,
1014                        true,
1015                        |a, b| a.wrapping_sub(b),
1016                    );
1017                }
1018            }
1019            // vwsub.wv - 2*SEW = 2*SEW - sext(SEW)
1020            Self::VwsubWv { vd, vs2, vs1, vm } => {
1021                if !ext_state.vector_instructions_allowed() {
1022                    Err(ExecutionError::IllegalInstruction {
1023                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1024                    })?;
1025                }
1026                let vtype = ext_state
1027                    .vtype()
1028                    .ok_or(ExecutionError::IllegalInstruction {
1029                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1030                    })?;
1031                let sew = vtype.vsew();
1032                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
1033                    Err(ExecutionError::IllegalInstruction {
1034                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1035                    })?;
1036                }
1037                let group_regs = vtype.vlmul().register_count();
1038                let wide_eew = match sew {
1039                    Vsew::E8 => Eew::E16,
1040                    Vsew::E16 => Eew::E32,
1041                    Vsew::E32 => Eew::E64,
1042                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
1043                };
1044                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
1045                    ExecutionError::IllegalInstruction {
1046                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1047                    },
1048                )?;
1049                zve64x_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _, _>(
1050                    program_counter,
1051                    vs2,
1052                    wide_group_regs,
1053                )?;
1054                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1055                    program_counter,
1056                    vs1,
1057                    group_regs,
1058                )?;
1059                zve64x_widen_narrow_helpers::check_vd_widen_alignment::<Reg, _, _, _>(
1060                    program_counter,
1061                    vd,
1062                    vs1,
1063                    None,
1064                    group_regs,
1065                    wide_group_regs,
1066                )?;
1067                if !vm && vd.bits() == 0 {
1068                    Err(ExecutionError::IllegalInstruction {
1069                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1070                    })?;
1071                }
1072                let vl = ext_state.vl();
1073                let vstart = u32::from(ext_state.vstart());
1074                // SAFETY: alignment/overlap/SEW checked above
1075                unsafe {
1076                    zve64x_widen_narrow_helpers::execute_widen_w_op(
1077                        ext_state,
1078                        vd,
1079                        vs2,
1080                        zve64x_widen_narrow_helpers::OpSrc::Vreg(vs1.bits()),
1081                        vm,
1082                        vl,
1083                        vstart,
1084                        sew,
1085                        false,
1086                        |a, b| a.wrapping_sub(b),
1087                    );
1088                }
1089            }
1090            // vwsub.wx - 2*SEW = 2*SEW - sext(rs1)
1091            Self::VwsubWx { vd, vs2, rs1, vm } => {
1092                if !ext_state.vector_instructions_allowed() {
1093                    Err(ExecutionError::IllegalInstruction {
1094                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1095                    })?;
1096                }
1097                let vtype = ext_state
1098                    .vtype()
1099                    .ok_or(ExecutionError::IllegalInstruction {
1100                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1101                    })?;
1102                let sew = vtype.vsew();
1103                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
1104                    Err(ExecutionError::IllegalInstruction {
1105                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1106                    })?;
1107                }
1108                let wide_eew = match sew {
1109                    Vsew::E8 => Eew::E16,
1110                    Vsew::E16 => Eew::E32,
1111                    Vsew::E32 => Eew::E64,
1112                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
1113                };
1114                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
1115                    ExecutionError::IllegalInstruction {
1116                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1117                    },
1118                )?;
1119                zve64x_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _, _>(
1120                    program_counter,
1121                    vs2,
1122                    wide_group_regs,
1123                )?;
1124                zve64x_widen_narrow_helpers::check_vd_widen_no_src_check::<Reg, _, _, _>(
1125                    program_counter,
1126                    vd,
1127                    wide_group_regs,
1128                )?;
1129                if !vm && vd.bits() == 0 {
1130                    Err(ExecutionError::IllegalInstruction {
1131                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1132                    })?;
1133                }
1134                let vl = ext_state.vl();
1135                let vstart = u32::from(ext_state.vstart());
1136                let scalar = zve64x_widen_narrow_helpers::sign_extend_bits(
1137                    regs.read(rs1).as_u64(),
1138                    u32::from(Reg::XLEN),
1139                )
1140                .cast_unsigned();
1141                // SAFETY: alignment/overlap/SEW checked above
1142                unsafe {
1143                    zve64x_widen_narrow_helpers::execute_widen_w_op(
1144                        ext_state,
1145                        vd,
1146                        vs2,
1147                        zve64x_widen_narrow_helpers::OpSrc::Scalar(scalar),
1148                        vm,
1149                        vl,
1150                        vstart,
1151                        sew,
1152                        false,
1153                        |a, b| a.wrapping_sub(b),
1154                    );
1155                }
1156            }
1157            // vnsrl.wv - SEW = (2*SEW) >> SEW (logical)
1158            Self::VnsrlWv { vd, vs2, vs1, vm } => {
1159                if !ext_state.vector_instructions_allowed() {
1160                    Err(ExecutionError::IllegalInstruction {
1161                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1162                    })?;
1163                }
1164                let vtype = ext_state
1165                    .vtype()
1166                    .ok_or(ExecutionError::IllegalInstruction {
1167                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1168                    })?;
1169                let sew = vtype.vsew();
1170                // SEW must be < 64 so that 2*SEW fits in ELEN
1171                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
1172                    Err(ExecutionError::IllegalInstruction {
1173                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1174                    })?;
1175                }
1176                let group_regs = vtype.vlmul().register_count();
1177                let wide_eew = match sew {
1178                    Vsew::E8 => Eew::E16,
1179                    Vsew::E16 => Eew::E32,
1180                    Vsew::E32 => Eew::E64,
1181                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
1182                };
1183                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
1184                    ExecutionError::IllegalInstruction {
1185                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1186                    },
1187                )?;
1188                zve64x_widen_narrow_helpers::check_vd_narrow_alignment::<Reg, _, _, _>(
1189                    program_counter,
1190                    vd,
1191                    group_regs,
1192                )?;
1193                zve64x_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _, _>(
1194                    program_counter,
1195                    vs2,
1196                    wide_group_regs,
1197                )?;
1198                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1199                    program_counter,
1200                    vs1,
1201                    group_regs,
1202                )?;
1203                if !vm && vd.bits() == 0 {
1204                    Err(ExecutionError::IllegalInstruction {
1205                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1206                    })?;
1207                }
1208                let vl = ext_state.vl();
1209                let vstart = u32::from(ext_state.vstart());
1210                // SAFETY: alignment/overlap/SEW checked above
1211                unsafe {
1212                    zve64x_widen_narrow_helpers::execute_narrow_shift(
1213                        ext_state,
1214                        vd,
1215                        vs2,
1216                        zve64x_widen_narrow_helpers::OpSrc::Vreg(vs1.bits()),
1217                        vm,
1218                        vl,
1219                        vstart,
1220                        sew,
1221                        false,
1222                    );
1223                }
1224            }
1225            // vnsrl.wx - SEW = (2*SEW) >> rs1 (logical)
1226            Self::VnsrlWx { vd, vs2, rs1, vm } => {
1227                if !ext_state.vector_instructions_allowed() {
1228                    Err(ExecutionError::IllegalInstruction {
1229                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1230                    })?;
1231                }
1232                let vtype = ext_state
1233                    .vtype()
1234                    .ok_or(ExecutionError::IllegalInstruction {
1235                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1236                    })?;
1237                let sew = vtype.vsew();
1238                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
1239                    Err(ExecutionError::IllegalInstruction {
1240                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1241                    })?;
1242                }
1243                let group_regs = vtype.vlmul().register_count();
1244                let wide_eew = match sew {
1245                    Vsew::E8 => Eew::E16,
1246                    Vsew::E16 => Eew::E32,
1247                    Vsew::E32 => Eew::E64,
1248                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
1249                };
1250                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
1251                    ExecutionError::IllegalInstruction {
1252                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1253                    },
1254                )?;
1255                zve64x_widen_narrow_helpers::check_vd_narrow_alignment::<Reg, _, _, _>(
1256                    program_counter,
1257                    vd,
1258                    group_regs,
1259                )?;
1260                zve64x_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _, _>(
1261                    program_counter,
1262                    vs2,
1263                    wide_group_regs,
1264                )?;
1265                if !vm && vd.bits() == 0 {
1266                    Err(ExecutionError::IllegalInstruction {
1267                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1268                    })?;
1269                }
1270                let vl = ext_state.vl();
1271                let vstart = u32::from(ext_state.vstart());
1272                let scalar = regs.read(rs1).as_u64();
1273                // SAFETY: alignment/overlap/SEW checked above
1274                unsafe {
1275                    zve64x_widen_narrow_helpers::execute_narrow_shift(
1276                        ext_state,
1277                        vd,
1278                        vs2,
1279                        zve64x_widen_narrow_helpers::OpSrc::Scalar(scalar),
1280                        vm,
1281                        vl,
1282                        vstart,
1283                        sew,
1284                        false,
1285                    );
1286                }
1287            }
1288            // vnsrl.wi - SEW = (2*SEW) >> uimm (logical)
1289            Self::VnsrlWi { vd, vs2, uimm, vm } => {
1290                if !ext_state.vector_instructions_allowed() {
1291                    Err(ExecutionError::IllegalInstruction {
1292                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1293                    })?;
1294                }
1295                let vtype = ext_state
1296                    .vtype()
1297                    .ok_or(ExecutionError::IllegalInstruction {
1298                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1299                    })?;
1300                let sew = vtype.vsew();
1301                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
1302                    Err(ExecutionError::IllegalInstruction {
1303                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1304                    })?;
1305                }
1306                let group_regs = vtype.vlmul().register_count();
1307                let wide_eew = match sew {
1308                    Vsew::E8 => Eew::E16,
1309                    Vsew::E16 => Eew::E32,
1310                    Vsew::E32 => Eew::E64,
1311                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
1312                };
1313                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
1314                    ExecutionError::IllegalInstruction {
1315                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1316                    },
1317                )?;
1318                zve64x_widen_narrow_helpers::check_vd_narrow_alignment::<Reg, _, _, _>(
1319                    program_counter,
1320                    vd,
1321                    group_regs,
1322                )?;
1323                zve64x_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _, _>(
1324                    program_counter,
1325                    vs2,
1326                    wide_group_regs,
1327                )?;
1328                if !vm && vd.bits() == 0 {
1329                    Err(ExecutionError::IllegalInstruction {
1330                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1331                    })?;
1332                }
1333                let vl = ext_state.vl();
1334                let vstart = u32::from(ext_state.vstart());
1335                // SAFETY: alignment/overlap/SEW checked above
1336                unsafe {
1337                    zve64x_widen_narrow_helpers::execute_narrow_shift(
1338                        ext_state,
1339                        vd,
1340                        vs2,
1341                        zve64x_widen_narrow_helpers::OpSrc::Scalar(u64::from(uimm)),
1342                        vm,
1343                        vl,
1344                        vstart,
1345                        sew,
1346                        false,
1347                    );
1348                }
1349            }
1350            // vnsra.wv - SEW = (2*SEW) >> SEW (arithmetic)
1351            Self::VnsraWv { vd, vs2, vs1, vm } => {
1352                if !ext_state.vector_instructions_allowed() {
1353                    Err(ExecutionError::IllegalInstruction {
1354                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1355                    })?;
1356                }
1357                let vtype = ext_state
1358                    .vtype()
1359                    .ok_or(ExecutionError::IllegalInstruction {
1360                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1361                    })?;
1362                let sew = vtype.vsew();
1363                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
1364                    Err(ExecutionError::IllegalInstruction {
1365                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1366                    })?;
1367                }
1368                let group_regs = vtype.vlmul().register_count();
1369                let wide_eew = match sew {
1370                    Vsew::E8 => Eew::E16,
1371                    Vsew::E16 => Eew::E32,
1372                    Vsew::E32 => Eew::E64,
1373                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
1374                };
1375                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
1376                    ExecutionError::IllegalInstruction {
1377                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1378                    },
1379                )?;
1380                zve64x_widen_narrow_helpers::check_vd_narrow_alignment::<Reg, _, _, _>(
1381                    program_counter,
1382                    vd,
1383                    group_regs,
1384                )?;
1385                zve64x_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _, _>(
1386                    program_counter,
1387                    vs2,
1388                    wide_group_regs,
1389                )?;
1390                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1391                    program_counter,
1392                    vs1,
1393                    group_regs,
1394                )?;
1395                if !vm && vd.bits() == 0 {
1396                    Err(ExecutionError::IllegalInstruction {
1397                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1398                    })?;
1399                }
1400                let vl = ext_state.vl();
1401                let vstart = u32::from(ext_state.vstart());
1402                // SAFETY: alignment/overlap/SEW checked above
1403                unsafe {
1404                    zve64x_widen_narrow_helpers::execute_narrow_shift(
1405                        ext_state,
1406                        vd,
1407                        vs2,
1408                        zve64x_widen_narrow_helpers::OpSrc::Vreg(vs1.bits()),
1409                        vm,
1410                        vl,
1411                        vstart,
1412                        sew,
1413                        true,
1414                    );
1415                }
1416            }
1417            // vnsra.wx - SEW = (2*SEW) >> rs1 (arithmetic)
1418            Self::VnsraWx { vd, vs2, rs1, vm } => {
1419                if !ext_state.vector_instructions_allowed() {
1420                    Err(ExecutionError::IllegalInstruction {
1421                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1422                    })?;
1423                }
1424                let vtype = ext_state
1425                    .vtype()
1426                    .ok_or(ExecutionError::IllegalInstruction {
1427                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1428                    })?;
1429                let sew = vtype.vsew();
1430                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
1431                    Err(ExecutionError::IllegalInstruction {
1432                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1433                    })?;
1434                }
1435                let group_regs = vtype.vlmul().register_count();
1436                let wide_eew = match sew {
1437                    Vsew::E8 => Eew::E16,
1438                    Vsew::E16 => Eew::E32,
1439                    Vsew::E32 => Eew::E64,
1440                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
1441                };
1442                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
1443                    ExecutionError::IllegalInstruction {
1444                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1445                    },
1446                )?;
1447                zve64x_widen_narrow_helpers::check_vd_narrow_alignment::<Reg, _, _, _>(
1448                    program_counter,
1449                    vd,
1450                    group_regs,
1451                )?;
1452                zve64x_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _, _>(
1453                    program_counter,
1454                    vs2,
1455                    wide_group_regs,
1456                )?;
1457                if !vm && vd.bits() == 0 {
1458                    Err(ExecutionError::IllegalInstruction {
1459                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1460                    })?;
1461                }
1462                let vl = ext_state.vl();
1463                let vstart = u32::from(ext_state.vstart());
1464                let scalar = regs.read(rs1).as_u64();
1465                // SAFETY: alignment/overlap/SEW checked above
1466                unsafe {
1467                    zve64x_widen_narrow_helpers::execute_narrow_shift(
1468                        ext_state,
1469                        vd,
1470                        vs2,
1471                        zve64x_widen_narrow_helpers::OpSrc::Scalar(scalar),
1472                        vm,
1473                        vl,
1474                        vstart,
1475                        sew,
1476                        true,
1477                    );
1478                }
1479            }
1480            // vnsra.wi - SEW = (2*SEW) >> uimm (arithmetic)
1481            Self::VnsraWi { vd, vs2, uimm, vm } => {
1482                if !ext_state.vector_instructions_allowed() {
1483                    Err(ExecutionError::IllegalInstruction {
1484                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1485                    })?;
1486                }
1487                let vtype = ext_state
1488                    .vtype()
1489                    .ok_or(ExecutionError::IllegalInstruction {
1490                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1491                    })?;
1492                let sew = vtype.vsew();
1493                if u32::from(sew.bits()) * 2 > ExtState::ELEN {
1494                    Err(ExecutionError::IllegalInstruction {
1495                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1496                    })?;
1497                }
1498                let group_regs = vtype.vlmul().register_count();
1499                let wide_eew = match sew {
1500                    Vsew::E8 => Eew::E16,
1501                    Vsew::E16 => Eew::E32,
1502                    Vsew::E32 => Eew::E64,
1503                    Vsew::E64 => unreachable!("SEW=64 already rejected above"),
1504                };
1505                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
1506                    ExecutionError::IllegalInstruction {
1507                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1508                    },
1509                )?;
1510                zve64x_widen_narrow_helpers::check_vd_narrow_alignment::<Reg, _, _, _>(
1511                    program_counter,
1512                    vd,
1513                    group_regs,
1514                )?;
1515                zve64x_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _, _>(
1516                    program_counter,
1517                    vs2,
1518                    wide_group_regs,
1519                )?;
1520                if !vm && vd.bits() == 0 {
1521                    Err(ExecutionError::IllegalInstruction {
1522                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1523                    })?;
1524                }
1525                let vl = ext_state.vl();
1526                let vstart = u32::from(ext_state.vstart());
1527                // SAFETY: alignment/overlap/SEW checked above
1528                unsafe {
1529                    zve64x_widen_narrow_helpers::execute_narrow_shift(
1530                        ext_state,
1531                        vd,
1532                        vs2,
1533                        zve64x_widen_narrow_helpers::OpSrc::Scalar(u64::from(uimm)),
1534                        vm,
1535                        vl,
1536                        vstart,
1537                        sew,
1538                        true,
1539                    );
1540                }
1541            }
1542            // vzext.vf2 - zero-extend SEW/2 -> SEW
1543            Self::VzextVf2 { vd, vs2, vm } => {
1544                if !ext_state.vector_instructions_allowed() {
1545                    Err(ExecutionError::IllegalInstruction {
1546                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1547                    })?;
1548                }
1549                let vtype = ext_state
1550                    .vtype()
1551                    .ok_or(ExecutionError::IllegalInstruction {
1552                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1553                    })?;
1554                let sew = vtype.vsew();
1555                // SEW must be >= 2*8 = 16
1556                if u32::from(sew.bits()) < 16 {
1557                    Err(ExecutionError::IllegalInstruction {
1558                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1559                    })?;
1560                }
1561                let group_regs = vtype.vlmul().register_count();
1562                // EMUL for source = LMUL / 2; src_group = max(1, group_regs / 2)
1563                let src_group = group_regs.max(2) / 2;
1564                zve64x_widen_narrow_helpers::check_vs_ext_alignment::<Reg, _, _, _>(
1565                    program_counter,
1566                    vs2,
1567                    src_group,
1568                    vd,
1569                    group_regs,
1570                )?;
1571                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1572                    program_counter,
1573                    vd,
1574                    group_regs,
1575                )?;
1576                if !vm && vd.bits() == 0 {
1577                    Err(ExecutionError::IllegalInstruction {
1578                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1579                    })?;
1580                }
1581                let vl = ext_state.vl();
1582                let vstart = u32::from(ext_state.vstart());
1583                // SAFETY: alignment/overlap/SEW checked above
1584                unsafe {
1585                    zve64x_widen_narrow_helpers::execute_extension(
1586                        ext_state, vd, vs2, vm, vl, vstart, sew, 2, false,
1587                    );
1588                }
1589            }
1590            // vzext.vf4 - zero-extend SEW/4 -> SEW
1591            Self::VzextVf4 { vd, vs2, vm } => {
1592                if !ext_state.vector_instructions_allowed() {
1593                    Err(ExecutionError::IllegalInstruction {
1594                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1595                    })?;
1596                }
1597                let vtype = ext_state
1598                    .vtype()
1599                    .ok_or(ExecutionError::IllegalInstruction {
1600                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1601                    })?;
1602                let sew = vtype.vsew();
1603                // SEW must be >= 4*8 = 32
1604                if u32::from(sew.bits()) < 32 {
1605                    Err(ExecutionError::IllegalInstruction {
1606                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1607                    })?;
1608                }
1609                let group_regs = vtype.vlmul().register_count();
1610                let src_group = group_regs.max(4) / 4;
1611                zve64x_widen_narrow_helpers::check_vs_ext_alignment::<Reg, _, _, _>(
1612                    program_counter,
1613                    vs2,
1614                    src_group,
1615                    vd,
1616                    group_regs,
1617                )?;
1618                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1619                    program_counter,
1620                    vd,
1621                    group_regs,
1622                )?;
1623                if !vm && vd.bits() == 0 {
1624                    Err(ExecutionError::IllegalInstruction {
1625                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1626                    })?;
1627                }
1628                let vl = ext_state.vl();
1629                let vstart = u32::from(ext_state.vstart());
1630                // SAFETY: alignment/overlap/SEW checked above
1631                unsafe {
1632                    zve64x_widen_narrow_helpers::execute_extension(
1633                        ext_state, vd, vs2, vm, vl, vstart, sew, 4, false,
1634                    );
1635                }
1636            }
1637            // vzext.vf8 - zero-extend SEW/8 -> SEW
1638            Self::VzextVf8 { vd, vs2, vm } => {
1639                if !ext_state.vector_instructions_allowed() {
1640                    Err(ExecutionError::IllegalInstruction {
1641                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1642                    })?;
1643                }
1644                let vtype = ext_state
1645                    .vtype()
1646                    .ok_or(ExecutionError::IllegalInstruction {
1647                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1648                    })?;
1649                let sew = vtype.vsew();
1650                // SEW must be >= 8*8 = 64; only SEW=64 qualifies in Zve64x
1651                if u32::from(sew.bits()) < 64 {
1652                    Err(ExecutionError::IllegalInstruction {
1653                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1654                    })?;
1655                }
1656                let group_regs = vtype.vlmul().register_count();
1657                let src_group = group_regs.max(8) / 8;
1658                zve64x_widen_narrow_helpers::check_vs_ext_alignment::<Reg, _, _, _>(
1659                    program_counter,
1660                    vs2,
1661                    src_group,
1662                    vd,
1663                    group_regs,
1664                )?;
1665                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1666                    program_counter,
1667                    vd,
1668                    group_regs,
1669                )?;
1670                if !vm && vd.bits() == 0 {
1671                    Err(ExecutionError::IllegalInstruction {
1672                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1673                    })?;
1674                }
1675                let vl = ext_state.vl();
1676                let vstart = u32::from(ext_state.vstart());
1677                // SAFETY: alignment/overlap/SEW checked above
1678                unsafe {
1679                    zve64x_widen_narrow_helpers::execute_extension(
1680                        ext_state, vd, vs2, vm, vl, vstart, sew, 8, false,
1681                    );
1682                }
1683            }
1684            // vsext.vf2 - sign-extend SEW/2 -> SEW
1685            Self::VsextVf2 { vd, vs2, vm } => {
1686                if !ext_state.vector_instructions_allowed() {
1687                    Err(ExecutionError::IllegalInstruction {
1688                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1689                    })?;
1690                }
1691                let vtype = ext_state
1692                    .vtype()
1693                    .ok_or(ExecutionError::IllegalInstruction {
1694                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1695                    })?;
1696                let sew = vtype.vsew();
1697                if u32::from(sew.bits()) < 16 {
1698                    Err(ExecutionError::IllegalInstruction {
1699                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1700                    })?;
1701                }
1702                let group_regs = vtype.vlmul().register_count();
1703                let src_group = group_regs.max(2) / 2;
1704                zve64x_widen_narrow_helpers::check_vs_ext_alignment::<Reg, _, _, _>(
1705                    program_counter,
1706                    vs2,
1707                    src_group,
1708                    vd,
1709                    group_regs,
1710                )?;
1711                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1712                    program_counter,
1713                    vd,
1714                    group_regs,
1715                )?;
1716                if !vm && vd.bits() == 0 {
1717                    Err(ExecutionError::IllegalInstruction {
1718                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1719                    })?;
1720                }
1721                let vl = ext_state.vl();
1722                let vstart = u32::from(ext_state.vstart());
1723                // SAFETY: alignment/overlap/SEW checked above
1724                unsafe {
1725                    zve64x_widen_narrow_helpers::execute_extension(
1726                        ext_state, vd, vs2, vm, vl, vstart, sew, 2, true,
1727                    );
1728                }
1729            }
1730            // vsext.vf4 - sign-extend SEW/4 -> SEW
1731            Self::VsextVf4 { vd, vs2, vm } => {
1732                if !ext_state.vector_instructions_allowed() {
1733                    Err(ExecutionError::IllegalInstruction {
1734                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1735                    })?;
1736                }
1737                let vtype = ext_state
1738                    .vtype()
1739                    .ok_or(ExecutionError::IllegalInstruction {
1740                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1741                    })?;
1742                let sew = vtype.vsew();
1743                if u32::from(sew.bits()) < 32 {
1744                    Err(ExecutionError::IllegalInstruction {
1745                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1746                    })?;
1747                }
1748                let group_regs = vtype.vlmul().register_count();
1749                let src_group = group_regs.max(4) / 4;
1750                zve64x_widen_narrow_helpers::check_vs_ext_alignment::<Reg, _, _, _>(
1751                    program_counter,
1752                    vs2,
1753                    src_group,
1754                    vd,
1755                    group_regs,
1756                )?;
1757                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1758                    program_counter,
1759                    vd,
1760                    group_regs,
1761                )?;
1762                if !vm && vd.bits() == 0 {
1763                    Err(ExecutionError::IllegalInstruction {
1764                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1765                    })?;
1766                }
1767                let vl = ext_state.vl();
1768                let vstart = u32::from(ext_state.vstart());
1769                // SAFETY: alignment/overlap/SEW checked above
1770                unsafe {
1771                    zve64x_widen_narrow_helpers::execute_extension(
1772                        ext_state, vd, vs2, vm, vl, vstart, sew, 4, true,
1773                    );
1774                }
1775            }
1776            // vsext.vf8 - sign-extend SEW/8 -> SEW
1777            Self::VsextVf8 { vd, vs2, vm } => {
1778                if !ext_state.vector_instructions_allowed() {
1779                    Err(ExecutionError::IllegalInstruction {
1780                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1781                    })?;
1782                }
1783                let vtype = ext_state
1784                    .vtype()
1785                    .ok_or(ExecutionError::IllegalInstruction {
1786                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1787                    })?;
1788                let sew = vtype.vsew();
1789                if u32::from(sew.bits()) < 64 {
1790                    Err(ExecutionError::IllegalInstruction {
1791                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1792                    })?;
1793                }
1794                let group_regs = vtype.vlmul().register_count();
1795                let src_group = group_regs.max(8) / 8;
1796                zve64x_widen_narrow_helpers::check_vs_ext_alignment::<Reg, _, _, _>(
1797                    program_counter,
1798                    vs2,
1799                    src_group,
1800                    vd,
1801                    group_regs,
1802                )?;
1803                zve64x_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1804                    program_counter,
1805                    vd,
1806                    group_regs,
1807                )?;
1808                if !vm && vd.bits() == 0 {
1809                    Err(ExecutionError::IllegalInstruction {
1810                        address: program_counter.old_pc(zve64x_helpers::INSTRUCTION_SIZE),
1811                    })?;
1812                }
1813                let vl = ext_state.vl();
1814                let vstart = u32::from(ext_state.vstart());
1815                // SAFETY: alignment/overlap/SEW checked above
1816                unsafe {
1817                    zve64x_widen_narrow_helpers::execute_extension(
1818                        ext_state, vd, vs2, vm, vl, vstart, sew, 8, true,
1819                    );
1820                }
1821            }
1822        }
1823
1824        Ok(ControlFlow::Continue(()))
1825    }
1826}