Skip to main content

ab_riscv_interpreter/v/zvexx/
widen_narrow.rs

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