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