Skip to main content

ab_riscv_interpreter/v/zvexx/
arith.rs

1//! ZveXx integer arithmetic instructions
2
3#[cfg(test)]
4mod tests;
5pub mod zvexx_arith_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 ZveXxArithInstruction<Reg> where Reg: Register {}
20
21#[instruction_execution]
22impl<Reg, ExtState, CustomError> ExecutableInstructionCsr<ExtState, CustomError>
23    for ZveXxArithInstruction<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 ZveXxArithInstruction<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            // vadd
60            Self::VaddVv { 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 group_regs = vtype.vlmul().register_count();
74                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
75                    program_counter,
76                    vd,
77                    group_regs,
78                )?;
79                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
80                    program_counter,
81                    vs2,
82                    group_regs,
83                )?;
84                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
85                    program_counter,
86                    vs1,
87                    group_regs,
88                )?;
89                if !vm && vd == VReg::V0 {
90                    ::core::hint::cold_path();
91                    return Err(ExecutionError::IllegalInstruction {
92                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
93                    });
94                }
95                let sew = vtype.vsew();
96                // SAFETY: alignment checked above; `vl <= VLMAX = group_regs * VLEN.bytes() /
97                // sew_bytes`; masked vd != v0 checked above.
98                unsafe {
99                    zvexx_arith_helpers::execute_arith_op(
100                        ext_state,
101                        vd,
102                        vs2,
103                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
104                        vm,
105                        sew,
106                        |a, b, _| a.wrapping_add(b),
107                    );
108                }
109            }
110            Self::VaddVx {
111                vd,
112                vs2,
113                rs1: _,
114                vm,
115            } => {
116                if !ext_state.vector_instructions_allowed() {
117                    ::core::hint::cold_path();
118                    return Err(ExecutionError::IllegalInstruction {
119                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
120                    });
121                }
122                let Some(vtype) = ext_state.vtype() else {
123                    ::core::hint::cold_path();
124                    return Err(ExecutionError::IllegalInstruction {
125                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
126                    });
127                };
128                let group_regs = vtype.vlmul().register_count();
129                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
130                    program_counter,
131                    vd,
132                    group_regs,
133                )?;
134                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
135                    program_counter,
136                    vs2,
137                    group_regs,
138                )?;
139                if !vm && vd == VReg::V0 {
140                    ::core::hint::cold_path();
141                    return Err(ExecutionError::IllegalInstruction {
142                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
143                    });
144                }
145                let sew = vtype.vsew();
146                let scalar = rs1_value.as_i64().cast_unsigned();
147                // SAFETY: alignment checked above; scalar source has no register constraints
148                unsafe {
149                    zvexx_arith_helpers::execute_arith_op(
150                        ext_state,
151                        vd,
152                        vs2,
153                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
154                        vm,
155                        sew,
156                        |a, b, _| a.wrapping_add(b),
157                    );
158                }
159            }
160            Self::VaddVi { vd, vs2, imm, vm } => {
161                if !ext_state.vector_instructions_allowed() {
162                    ::core::hint::cold_path();
163                    return Err(ExecutionError::IllegalInstruction {
164                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
165                    });
166                }
167                let Some(vtype) = ext_state.vtype() else {
168                    ::core::hint::cold_path();
169                    return Err(ExecutionError::IllegalInstruction {
170                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
171                    });
172                };
173                let group_regs = vtype.vlmul().register_count();
174                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
175                    program_counter,
176                    vd,
177                    group_regs,
178                )?;
179                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
180                    program_counter,
181                    vs2,
182                    group_regs,
183                )?;
184                if !vm && vd == VReg::V0 {
185                    ::core::hint::cold_path();
186                    return Err(ExecutionError::IllegalInstruction {
187                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
188                    });
189                }
190                let sew = vtype.vsew();
191                // Sign-extend imm to u64 so wrapping_add works correctly for all SEW
192                let scalar = i64::from(imm).cast_unsigned();
193                // SAFETY: alignment checked above
194                unsafe {
195                    zvexx_arith_helpers::execute_arith_op(
196                        ext_state,
197                        vd,
198                        vs2,
199                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
200                        vm,
201                        sew,
202                        |a, b, _| a.wrapping_add(b),
203                    );
204                }
205            }
206            // vsub / vrsub
207            Self::VsubVv { vd, vs2, vs1, vm } => {
208                if !ext_state.vector_instructions_allowed() {
209                    ::core::hint::cold_path();
210                    return Err(ExecutionError::IllegalInstruction {
211                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
212                    });
213                }
214                let Some(vtype) = ext_state.vtype() else {
215                    ::core::hint::cold_path();
216                    return Err(ExecutionError::IllegalInstruction {
217                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
218                    });
219                };
220                let group_regs = vtype.vlmul().register_count();
221                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
222                    program_counter,
223                    vd,
224                    group_regs,
225                )?;
226                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
227                    program_counter,
228                    vs2,
229                    group_regs,
230                )?;
231                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
232                    program_counter,
233                    vs1,
234                    group_regs,
235                )?;
236                if !vm && vd == VReg::V0 {
237                    ::core::hint::cold_path();
238                    return Err(ExecutionError::IllegalInstruction {
239                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
240                    });
241                }
242                let sew = vtype.vsew();
243                // SAFETY: alignment checked above
244                unsafe {
245                    zvexx_arith_helpers::execute_arith_op(
246                        ext_state,
247                        vd,
248                        vs2,
249                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
250                        vm,
251                        sew,
252                        |a, b, _| a.wrapping_sub(b),
253                    );
254                }
255            }
256            Self::VsubVx {
257                vd,
258                vs2,
259                rs1: _,
260                vm,
261            } => {
262                if !ext_state.vector_instructions_allowed() {
263                    ::core::hint::cold_path();
264                    return Err(ExecutionError::IllegalInstruction {
265                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
266                    });
267                }
268                let Some(vtype) = ext_state.vtype() else {
269                    ::core::hint::cold_path();
270                    return Err(ExecutionError::IllegalInstruction {
271                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
272                    });
273                };
274                let group_regs = vtype.vlmul().register_count();
275                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
276                    program_counter,
277                    vd,
278                    group_regs,
279                )?;
280                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
281                    program_counter,
282                    vs2,
283                    group_regs,
284                )?;
285                if !vm && vd == VReg::V0 {
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                let scalar = rs1_value.as_i64().cast_unsigned();
293                // SAFETY: alignment checked above
294                unsafe {
295                    zvexx_arith_helpers::execute_arith_op(
296                        ext_state,
297                        vd,
298                        vs2,
299                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
300                        vm,
301                        sew,
302                        |a, b, _| a.wrapping_sub(b),
303                    );
304                }
305            }
306            Self::VrsubVx {
307                vd,
308                vs2,
309                rs1: _,
310                vm,
311            } => {
312                if !ext_state.vector_instructions_allowed() {
313                    ::core::hint::cold_path();
314                    return Err(ExecutionError::IllegalInstruction {
315                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
316                    });
317                }
318                let Some(vtype) = ext_state.vtype() else {
319                    ::core::hint::cold_path();
320                    return Err(ExecutionError::IllegalInstruction {
321                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
322                    });
323                };
324                let group_regs = vtype.vlmul().register_count();
325                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
326                    program_counter,
327                    vd,
328                    group_regs,
329                )?;
330                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
331                    program_counter,
332                    vs2,
333                    group_regs,
334                )?;
335                if !vm && vd == VReg::V0 {
336                    ::core::hint::cold_path();
337                    return Err(ExecutionError::IllegalInstruction {
338                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
339                    });
340                }
341                let sew = vtype.vsew();
342                let scalar = rs1_value.as_i64().cast_unsigned();
343                // vrsub: result = src - vs2[i]
344                // SAFETY: alignment checked above
345                unsafe {
346                    zvexx_arith_helpers::execute_arith_op(
347                        ext_state,
348                        vd,
349                        vs2,
350                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
351                        vm,
352                        sew,
353                        |a, b, _| b.wrapping_sub(a),
354                    );
355                }
356            }
357            Self::VrsubVi { vd, vs2, imm, vm } => {
358                if !ext_state.vector_instructions_allowed() {
359                    ::core::hint::cold_path();
360                    return Err(ExecutionError::IllegalInstruction {
361                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
362                    });
363                }
364                let Some(vtype) = ext_state.vtype() else {
365                    ::core::hint::cold_path();
366                    return Err(ExecutionError::IllegalInstruction {
367                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
368                    });
369                };
370                let group_regs = vtype.vlmul().register_count();
371                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
372                    program_counter,
373                    vd,
374                    group_regs,
375                )?;
376                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
377                    program_counter,
378                    vs2,
379                    group_regs,
380                )?;
381                if !vm && vd == VReg::V0 {
382                    ::core::hint::cold_path();
383                    return Err(ExecutionError::IllegalInstruction {
384                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
385                    });
386                }
387                let sew = vtype.vsew();
388                let scalar = i64::from(imm).cast_unsigned();
389                // SAFETY: alignment checked above
390                unsafe {
391                    zvexx_arith_helpers::execute_arith_op(
392                        ext_state,
393                        vd,
394                        vs2,
395                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
396                        vm,
397                        sew,
398                        |a, b, _| b.wrapping_sub(a),
399                    );
400                }
401            }
402            // vand
403            Self::VandVv { vd, vs2, vs1, vm } => {
404                if !ext_state.vector_instructions_allowed() {
405                    ::core::hint::cold_path();
406                    return Err(ExecutionError::IllegalInstruction {
407                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
408                    });
409                }
410                let Some(vtype) = ext_state.vtype() else {
411                    ::core::hint::cold_path();
412                    return Err(ExecutionError::IllegalInstruction {
413                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
414                    });
415                };
416                let group_regs = vtype.vlmul().register_count();
417                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
418                    program_counter,
419                    vd,
420                    group_regs,
421                )?;
422                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
423                    program_counter,
424                    vs2,
425                    group_regs,
426                )?;
427                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
428                    program_counter,
429                    vs1,
430                    group_regs,
431                )?;
432                if !vm && vd == VReg::V0 {
433                    ::core::hint::cold_path();
434                    return Err(ExecutionError::IllegalInstruction {
435                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
436                    });
437                }
438                let sew = vtype.vsew();
439                // SAFETY: alignment checked above
440                unsafe {
441                    zvexx_arith_helpers::execute_arith_op(
442                        ext_state,
443                        vd,
444                        vs2,
445                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
446                        vm,
447                        sew,
448                        |a, b, _| a & b,
449                    );
450                }
451            }
452            Self::VandVx {
453                vd,
454                vs2,
455                rs1: _,
456                vm,
457            } => {
458                if !ext_state.vector_instructions_allowed() {
459                    ::core::hint::cold_path();
460                    return Err(ExecutionError::IllegalInstruction {
461                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
462                    });
463                }
464                let Some(vtype) = ext_state.vtype() else {
465                    ::core::hint::cold_path();
466                    return Err(ExecutionError::IllegalInstruction {
467                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
468                    });
469                };
470                let group_regs = vtype.vlmul().register_count();
471                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
472                    program_counter,
473                    vd,
474                    group_regs,
475                )?;
476                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
477                    program_counter,
478                    vs2,
479                    group_regs,
480                )?;
481                if !vm && vd == VReg::V0 {
482                    ::core::hint::cold_path();
483                    return Err(ExecutionError::IllegalInstruction {
484                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
485                    });
486                }
487                let sew = vtype.vsew();
488                let scalar = rs1_value.as_i64().cast_unsigned();
489                // SAFETY: alignment checked above
490                unsafe {
491                    zvexx_arith_helpers::execute_arith_op(
492                        ext_state,
493                        vd,
494                        vs2,
495                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
496                        vm,
497                        sew,
498                        |a, b, _| a & b,
499                    );
500                }
501            }
502            Self::VandVi { vd, vs2, imm, vm } => {
503                if !ext_state.vector_instructions_allowed() {
504                    ::core::hint::cold_path();
505                    return Err(ExecutionError::IllegalInstruction {
506                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
507                    });
508                }
509                let Some(vtype) = ext_state.vtype() else {
510                    ::core::hint::cold_path();
511                    return Err(ExecutionError::IllegalInstruction {
512                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
513                    });
514                };
515                let group_regs = vtype.vlmul().register_count();
516                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
517                    program_counter,
518                    vd,
519                    group_regs,
520                )?;
521                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
522                    program_counter,
523                    vs2,
524                    group_regs,
525                )?;
526                if !vm && vd == VReg::V0 {
527                    ::core::hint::cold_path();
528                    return Err(ExecutionError::IllegalInstruction {
529                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
530                    });
531                }
532                let sew = vtype.vsew();
533                let scalar = i64::from(imm).cast_unsigned();
534                // SAFETY: alignment checked above
535                unsafe {
536                    zvexx_arith_helpers::execute_arith_op(
537                        ext_state,
538                        vd,
539                        vs2,
540                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
541                        vm,
542                        sew,
543                        |a, b, _| a & b,
544                    );
545                }
546            }
547            // vor
548            Self::VorVv { vd, vs2, vs1, vm } => {
549                if !ext_state.vector_instructions_allowed() {
550                    ::core::hint::cold_path();
551                    return Err(ExecutionError::IllegalInstruction {
552                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
553                    });
554                }
555                let Some(vtype) = ext_state.vtype() else {
556                    ::core::hint::cold_path();
557                    return Err(ExecutionError::IllegalInstruction {
558                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
559                    });
560                };
561                let group_regs = vtype.vlmul().register_count();
562                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
563                    program_counter,
564                    vd,
565                    group_regs,
566                )?;
567                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
568                    program_counter,
569                    vs2,
570                    group_regs,
571                )?;
572                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
573                    program_counter,
574                    vs1,
575                    group_regs,
576                )?;
577                if !vm && vd == VReg::V0 {
578                    ::core::hint::cold_path();
579                    return Err(ExecutionError::IllegalInstruction {
580                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
581                    });
582                }
583                let sew = vtype.vsew();
584                // SAFETY: alignment checked above
585                unsafe {
586                    zvexx_arith_helpers::execute_arith_op(
587                        ext_state,
588                        vd,
589                        vs2,
590                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
591                        vm,
592                        sew,
593                        |a, b, _| a | b,
594                    );
595                }
596            }
597            Self::VorVx {
598                vd,
599                vs2,
600                rs1: _,
601                vm,
602            } => {
603                if !ext_state.vector_instructions_allowed() {
604                    ::core::hint::cold_path();
605                    return Err(ExecutionError::IllegalInstruction {
606                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
607                    });
608                }
609                let Some(vtype) = ext_state.vtype() else {
610                    ::core::hint::cold_path();
611                    return Err(ExecutionError::IllegalInstruction {
612                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
613                    });
614                };
615                let group_regs = vtype.vlmul().register_count();
616                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
617                    program_counter,
618                    vd,
619                    group_regs,
620                )?;
621                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
622                    program_counter,
623                    vs2,
624                    group_regs,
625                )?;
626                if !vm && vd == VReg::V0 {
627                    ::core::hint::cold_path();
628                    return Err(ExecutionError::IllegalInstruction {
629                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
630                    });
631                }
632                let sew = vtype.vsew();
633                let scalar = rs1_value.as_i64().cast_unsigned();
634                // SAFETY: alignment checked above
635                unsafe {
636                    zvexx_arith_helpers::execute_arith_op(
637                        ext_state,
638                        vd,
639                        vs2,
640                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
641                        vm,
642                        sew,
643                        |a, b, _| a | b,
644                    );
645                }
646            }
647            Self::VorVi { vd, vs2, imm, vm } => {
648                if !ext_state.vector_instructions_allowed() {
649                    ::core::hint::cold_path();
650                    return Err(ExecutionError::IllegalInstruction {
651                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
652                    });
653                }
654                let Some(vtype) = ext_state.vtype() else {
655                    ::core::hint::cold_path();
656                    return Err(ExecutionError::IllegalInstruction {
657                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
658                    });
659                };
660                let group_regs = vtype.vlmul().register_count();
661                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
662                    program_counter,
663                    vd,
664                    group_regs,
665                )?;
666                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
667                    program_counter,
668                    vs2,
669                    group_regs,
670                )?;
671                if !vm && vd == VReg::V0 {
672                    ::core::hint::cold_path();
673                    return Err(ExecutionError::IllegalInstruction {
674                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
675                    });
676                }
677                let sew = vtype.vsew();
678                let scalar = i64::from(imm).cast_unsigned();
679                // SAFETY: alignment checked above
680                unsafe {
681                    zvexx_arith_helpers::execute_arith_op(
682                        ext_state,
683                        vd,
684                        vs2,
685                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
686                        vm,
687                        sew,
688                        |a, b, _| a | b,
689                    );
690                }
691            }
692            // vxor
693            Self::VxorVv { vd, vs2, vs1, vm } => {
694                if !ext_state.vector_instructions_allowed() {
695                    ::core::hint::cold_path();
696                    return Err(ExecutionError::IllegalInstruction {
697                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
698                    });
699                }
700                let Some(vtype) = ext_state.vtype() else {
701                    ::core::hint::cold_path();
702                    return Err(ExecutionError::IllegalInstruction {
703                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
704                    });
705                };
706                let group_regs = vtype.vlmul().register_count();
707                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
708                    program_counter,
709                    vd,
710                    group_regs,
711                )?;
712                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
713                    program_counter,
714                    vs2,
715                    group_regs,
716                )?;
717                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
718                    program_counter,
719                    vs1,
720                    group_regs,
721                )?;
722                if !vm && vd == VReg::V0 {
723                    ::core::hint::cold_path();
724                    return Err(ExecutionError::IllegalInstruction {
725                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
726                    });
727                }
728                let sew = vtype.vsew();
729                // SAFETY: alignment checked above
730                unsafe {
731                    zvexx_arith_helpers::execute_arith_op(
732                        ext_state,
733                        vd,
734                        vs2,
735                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
736                        vm,
737                        sew,
738                        |a, b, _| a ^ b,
739                    );
740                }
741            }
742            Self::VxorVx {
743                vd,
744                vs2,
745                rs1: _,
746                vm,
747            } => {
748                if !ext_state.vector_instructions_allowed() {
749                    ::core::hint::cold_path();
750                    return Err(ExecutionError::IllegalInstruction {
751                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
752                    });
753                }
754                let Some(vtype) = ext_state.vtype() else {
755                    ::core::hint::cold_path();
756                    return Err(ExecutionError::IllegalInstruction {
757                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
758                    });
759                };
760                let group_regs = vtype.vlmul().register_count();
761                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
762                    program_counter,
763                    vd,
764                    group_regs,
765                )?;
766                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
767                    program_counter,
768                    vs2,
769                    group_regs,
770                )?;
771                if !vm && vd == VReg::V0 {
772                    ::core::hint::cold_path();
773                    return Err(ExecutionError::IllegalInstruction {
774                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
775                    });
776                }
777                let sew = vtype.vsew();
778                let scalar = rs1_value.as_i64().cast_unsigned();
779                // SAFETY: alignment checked above
780                unsafe {
781                    zvexx_arith_helpers::execute_arith_op(
782                        ext_state,
783                        vd,
784                        vs2,
785                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
786                        vm,
787                        sew,
788                        |a, b, _| a ^ b,
789                    );
790                }
791            }
792            Self::VxorVi { vd, vs2, imm, vm } => {
793                if !ext_state.vector_instructions_allowed() {
794                    ::core::hint::cold_path();
795                    return Err(ExecutionError::IllegalInstruction {
796                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
797                    });
798                }
799                let Some(vtype) = ext_state.vtype() else {
800                    ::core::hint::cold_path();
801                    return Err(ExecutionError::IllegalInstruction {
802                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
803                    });
804                };
805                let group_regs = vtype.vlmul().register_count();
806                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
807                    program_counter,
808                    vd,
809                    group_regs,
810                )?;
811                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
812                    program_counter,
813                    vs2,
814                    group_regs,
815                )?;
816                if !vm && vd == VReg::V0 {
817                    ::core::hint::cold_path();
818                    return Err(ExecutionError::IllegalInstruction {
819                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
820                    });
821                }
822                let sew = vtype.vsew();
823                let scalar = i64::from(imm).cast_unsigned();
824                // SAFETY: alignment checked above
825                unsafe {
826                    zvexx_arith_helpers::execute_arith_op(
827                        ext_state,
828                        vd,
829                        vs2,
830                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
831                        vm,
832                        sew,
833                        |a, b, _| a ^ b,
834                    );
835                }
836            }
837            // vsll
838            Self::VsllVv { vd, vs2, vs1, vm } => {
839                if !ext_state.vector_instructions_allowed() {
840                    ::core::hint::cold_path();
841                    return Err(ExecutionError::IllegalInstruction {
842                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
843                    });
844                }
845                let Some(vtype) = ext_state.vtype() else {
846                    ::core::hint::cold_path();
847                    return Err(ExecutionError::IllegalInstruction {
848                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
849                    });
850                };
851                let group_regs = vtype.vlmul().register_count();
852                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
853                    program_counter,
854                    vd,
855                    group_regs,
856                )?;
857                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
858                    program_counter,
859                    vs2,
860                    group_regs,
861                )?;
862                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
863                    program_counter,
864                    vs1,
865                    group_regs,
866                )?;
867                if !vm && vd == VReg::V0 {
868                    ::core::hint::cold_path();
869                    return Err(ExecutionError::IllegalInstruction {
870                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
871                    });
872                }
873                let sew = vtype.vsew();
874                // SAFETY: alignment checked above
875                unsafe {
876                    zvexx_arith_helpers::execute_arith_op(
877                        ext_state,
878                        vd,
879                        vs2,
880                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
881                        vm,
882                        sew,
883                        // Shift amount masked to log2(SEW) bits per spec ยง12.6
884                        |a, b, sew| a << (b & u64::from(sew.bits_width() - 1)),
885                    );
886                }
887            }
888            Self::VsllVx {
889                vd,
890                vs2,
891                rs1: _,
892                vm,
893            } => {
894                if !ext_state.vector_instructions_allowed() {
895                    ::core::hint::cold_path();
896                    return Err(ExecutionError::IllegalInstruction {
897                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
898                    });
899                }
900                let Some(vtype) = ext_state.vtype() else {
901                    ::core::hint::cold_path();
902                    return Err(ExecutionError::IllegalInstruction {
903                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
904                    });
905                };
906                let group_regs = vtype.vlmul().register_count();
907                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
908                    program_counter,
909                    vd,
910                    group_regs,
911                )?;
912                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
913                    program_counter,
914                    vs2,
915                    group_regs,
916                )?;
917                if !vm && vd == VReg::V0 {
918                    ::core::hint::cold_path();
919                    return Err(ExecutionError::IllegalInstruction {
920                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
921                    });
922                }
923                let sew = vtype.vsew();
924                let scalar = rs1_value.as_u64();
925                // SAFETY: alignment checked above
926                unsafe {
927                    zvexx_arith_helpers::execute_arith_op(
928                        ext_state,
929                        vd,
930                        vs2,
931                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
932                        vm,
933                        sew,
934                        |a, b, sew| a << (b & u64::from(sew.bits_width() - 1)),
935                    );
936                }
937            }
938            Self::VsllVi { vd, vs2, uimm, vm } => {
939                if !ext_state.vector_instructions_allowed() {
940                    ::core::hint::cold_path();
941                    return Err(ExecutionError::IllegalInstruction {
942                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
943                    });
944                }
945                let Some(vtype) = ext_state.vtype() else {
946                    ::core::hint::cold_path();
947                    return Err(ExecutionError::IllegalInstruction {
948                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
949                    });
950                };
951                let group_regs = vtype.vlmul().register_count();
952                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
953                    program_counter,
954                    vd,
955                    group_regs,
956                )?;
957                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
958                    program_counter,
959                    vs2,
960                    group_regs,
961                )?;
962                if !vm && vd == VReg::V0 {
963                    ::core::hint::cold_path();
964                    return Err(ExecutionError::IllegalInstruction {
965                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
966                    });
967                }
968                let sew = vtype.vsew();
969                // Immediate is already unsigned 5-bit; mask to log2(SEW) here too
970                let shamt = u64::from(uimm) & u64::from(sew.bits_width() - 1);
971                // SAFETY: alignment checked above
972                unsafe {
973                    zvexx_arith_helpers::execute_arith_op(
974                        ext_state,
975                        vd,
976                        vs2,
977                        zvexx_arith_helpers::OpSrc::Scalar(shamt),
978                        vm,
979                        sew,
980                        |a, b, _| a << b,
981                    );
982                }
983            }
984            // vsrl
985            Self::VsrlVv { vd, vs2, vs1, vm } => {
986                if !ext_state.vector_instructions_allowed() {
987                    ::core::hint::cold_path();
988                    return Err(ExecutionError::IllegalInstruction {
989                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
990                    });
991                }
992                let Some(vtype) = ext_state.vtype() else {
993                    ::core::hint::cold_path();
994                    return Err(ExecutionError::IllegalInstruction {
995                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
996                    });
997                };
998                let group_regs = vtype.vlmul().register_count();
999                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1000                    program_counter,
1001                    vd,
1002                    group_regs,
1003                )?;
1004                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1005                    program_counter,
1006                    vs2,
1007                    group_regs,
1008                )?;
1009                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1010                    program_counter,
1011                    vs1,
1012                    group_regs,
1013                )?;
1014                if !vm && vd == VReg::V0 {
1015                    ::core::hint::cold_path();
1016                    return Err(ExecutionError::IllegalInstruction {
1017                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1018                    });
1019                }
1020                let sew = vtype.vsew();
1021                // SAFETY: alignment checked above
1022                unsafe {
1023                    zvexx_arith_helpers::execute_arith_op(
1024                        ext_state,
1025                        vd,
1026                        vs2,
1027                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
1028                        vm,
1029                        sew,
1030                        // Logical right shift; operate on the SEW-wide portion only
1031                        |a, b, sew| {
1032                            let mask = zvexx_arith_helpers::sew_mask(sew);
1033                            let shamt = b & u64::from(sew.bits_width() - 1);
1034                            (a & mask) >> shamt
1035                        },
1036                    );
1037                }
1038            }
1039            Self::VsrlVx {
1040                vd,
1041                vs2,
1042                rs1: _,
1043                vm,
1044            } => {
1045                if !ext_state.vector_instructions_allowed() {
1046                    ::core::hint::cold_path();
1047                    return Err(ExecutionError::IllegalInstruction {
1048                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1049                    });
1050                }
1051                let Some(vtype) = ext_state.vtype() else {
1052                    ::core::hint::cold_path();
1053                    return Err(ExecutionError::IllegalInstruction {
1054                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1055                    });
1056                };
1057                let group_regs = vtype.vlmul().register_count();
1058                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1059                    program_counter,
1060                    vd,
1061                    group_regs,
1062                )?;
1063                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1064                    program_counter,
1065                    vs2,
1066                    group_regs,
1067                )?;
1068                if !vm && vd == VReg::V0 {
1069                    ::core::hint::cold_path();
1070                    return Err(ExecutionError::IllegalInstruction {
1071                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1072                    });
1073                }
1074                let sew = vtype.vsew();
1075                let scalar = rs1_value.as_u64();
1076                // SAFETY: alignment checked above
1077                unsafe {
1078                    zvexx_arith_helpers::execute_arith_op(
1079                        ext_state,
1080                        vd,
1081                        vs2,
1082                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
1083                        vm,
1084                        sew,
1085                        |a, b, sew| {
1086                            let mask = zvexx_arith_helpers::sew_mask(sew);
1087                            let shamt = b & u64::from(sew.bits_width() - 1);
1088                            (a & mask) >> shamt
1089                        },
1090                    );
1091                }
1092            }
1093            Self::VsrlVi { vd, vs2, uimm, vm } => {
1094                if !ext_state.vector_instructions_allowed() {
1095                    ::core::hint::cold_path();
1096                    return Err(ExecutionError::IllegalInstruction {
1097                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1098                    });
1099                }
1100                let Some(vtype) = ext_state.vtype() else {
1101                    ::core::hint::cold_path();
1102                    return Err(ExecutionError::IllegalInstruction {
1103                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1104                    });
1105                };
1106                let group_regs = vtype.vlmul().register_count();
1107                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1108                    program_counter,
1109                    vd,
1110                    group_regs,
1111                )?;
1112                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1113                    program_counter,
1114                    vs2,
1115                    group_regs,
1116                )?;
1117                if !vm && vd == VReg::V0 {
1118                    ::core::hint::cold_path();
1119                    return Err(ExecutionError::IllegalInstruction {
1120                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1121                    });
1122                }
1123                let sew = vtype.vsew();
1124                let shamt = u64::from(uimm) & u64::from(sew.bits_width() - 1);
1125                // SAFETY: alignment checked above
1126                unsafe {
1127                    zvexx_arith_helpers::execute_arith_op(
1128                        ext_state,
1129                        vd,
1130                        vs2,
1131                        zvexx_arith_helpers::OpSrc::Scalar(shamt),
1132                        vm,
1133                        sew,
1134                        |a, b, sew| (a & zvexx_arith_helpers::sew_mask(sew)) >> b,
1135                    );
1136                }
1137            }
1138            // vsra
1139            Self::VsraVv { vd, vs2, vs1, vm } => {
1140                if !ext_state.vector_instructions_allowed() {
1141                    ::core::hint::cold_path();
1142                    return Err(ExecutionError::IllegalInstruction {
1143                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1144                    });
1145                }
1146                let Some(vtype) = ext_state.vtype() else {
1147                    ::core::hint::cold_path();
1148                    return Err(ExecutionError::IllegalInstruction {
1149                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1150                    });
1151                };
1152                let group_regs = vtype.vlmul().register_count();
1153                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1154                    program_counter,
1155                    vd,
1156                    group_regs,
1157                )?;
1158                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1159                    program_counter,
1160                    vs2,
1161                    group_regs,
1162                )?;
1163                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1164                    program_counter,
1165                    vs1,
1166                    group_regs,
1167                )?;
1168                if !vm && vd == VReg::V0 {
1169                    ::core::hint::cold_path();
1170                    return Err(ExecutionError::IllegalInstruction {
1171                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1172                    });
1173                }
1174                let sew = vtype.vsew();
1175                // SAFETY: alignment checked above
1176                unsafe {
1177                    zvexx_arith_helpers::execute_arith_op(
1178                        ext_state,
1179                        vd,
1180                        vs2,
1181                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
1182                        vm,
1183                        sew,
1184                        |a, b, sew| {
1185                            let shamt = b & u64::from(sew.bits_width() - 1);
1186                            let signed = zvexx_arith_helpers::sign_extend(a, sew);
1187                            (signed >> shamt).cast_unsigned()
1188                        },
1189                    );
1190                }
1191            }
1192            Self::VsraVx {
1193                vd,
1194                vs2,
1195                rs1: _,
1196                vm,
1197            } => {
1198                if !ext_state.vector_instructions_allowed() {
1199                    ::core::hint::cold_path();
1200                    return Err(ExecutionError::IllegalInstruction {
1201                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1202                    });
1203                }
1204                let Some(vtype) = ext_state.vtype() else {
1205                    ::core::hint::cold_path();
1206                    return Err(ExecutionError::IllegalInstruction {
1207                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1208                    });
1209                };
1210                let group_regs = vtype.vlmul().register_count();
1211                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1212                    program_counter,
1213                    vd,
1214                    group_regs,
1215                )?;
1216                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1217                    program_counter,
1218                    vs2,
1219                    group_regs,
1220                )?;
1221                if !vm && vd == VReg::V0 {
1222                    ::core::hint::cold_path();
1223                    return Err(ExecutionError::IllegalInstruction {
1224                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1225                    });
1226                }
1227                let sew = vtype.vsew();
1228                let scalar = rs1_value.as_u64();
1229                // SAFETY: alignment checked above
1230                unsafe {
1231                    zvexx_arith_helpers::execute_arith_op(
1232                        ext_state,
1233                        vd,
1234                        vs2,
1235                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
1236                        vm,
1237                        sew,
1238                        |a, b, sew| {
1239                            let shamt = b & u64::from(sew.bits_width() - 1);
1240                            let signed = zvexx_arith_helpers::sign_extend(a, sew);
1241                            (signed >> shamt).cast_unsigned()
1242                        },
1243                    );
1244                }
1245            }
1246            Self::VsraVi { vd, vs2, uimm, vm } => {
1247                if !ext_state.vector_instructions_allowed() {
1248                    ::core::hint::cold_path();
1249                    return Err(ExecutionError::IllegalInstruction {
1250                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1251                    });
1252                }
1253                let Some(vtype) = ext_state.vtype() else {
1254                    ::core::hint::cold_path();
1255                    return Err(ExecutionError::IllegalInstruction {
1256                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1257                    });
1258                };
1259                let group_regs = vtype.vlmul().register_count();
1260                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1261                    program_counter,
1262                    vd,
1263                    group_regs,
1264                )?;
1265                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1266                    program_counter,
1267                    vs2,
1268                    group_regs,
1269                )?;
1270                if !vm && vd == VReg::V0 {
1271                    ::core::hint::cold_path();
1272                    return Err(ExecutionError::IllegalInstruction {
1273                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1274                    });
1275                }
1276                let sew = vtype.vsew();
1277                let shamt = u64::from(uimm) & u64::from(sew.bits_width() - 1);
1278                // SAFETY: alignment checked above
1279                unsafe {
1280                    zvexx_arith_helpers::execute_arith_op(
1281                        ext_state,
1282                        vd,
1283                        vs2,
1284                        zvexx_arith_helpers::OpSrc::Scalar(shamt),
1285                        vm,
1286                        sew,
1287                        |a, b, sew| {
1288                            let signed = zvexx_arith_helpers::sign_extend(a, sew);
1289                            (signed >> b).cast_unsigned()
1290                        },
1291                    );
1292                }
1293            }
1294            // vminu / vmin
1295            Self::VminuVv { vd, vs2, vs1, vm } => {
1296                if !ext_state.vector_instructions_allowed() {
1297                    ::core::hint::cold_path();
1298                    return Err(ExecutionError::IllegalInstruction {
1299                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1300                    });
1301                }
1302                let Some(vtype) = ext_state.vtype() else {
1303                    ::core::hint::cold_path();
1304                    return Err(ExecutionError::IllegalInstruction {
1305                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1306                    });
1307                };
1308                let group_regs = vtype.vlmul().register_count();
1309                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1310                    program_counter,
1311                    vd,
1312                    group_regs,
1313                )?;
1314                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1315                    program_counter,
1316                    vs2,
1317                    group_regs,
1318                )?;
1319                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1320                    program_counter,
1321                    vs1,
1322                    group_regs,
1323                )?;
1324                if !vm && vd == VReg::V0 {
1325                    ::core::hint::cold_path();
1326                    return Err(ExecutionError::IllegalInstruction {
1327                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1328                    });
1329                }
1330                let sew = vtype.vsew();
1331                // SAFETY: alignment checked above
1332                unsafe {
1333                    zvexx_arith_helpers::execute_arith_op(
1334                        ext_state,
1335                        vd,
1336                        vs2,
1337                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
1338                        vm,
1339                        sew,
1340                        |a, b, sew| {
1341                            let mask = zvexx_arith_helpers::sew_mask(sew);
1342                            if a & mask <= b & mask { a } else { b }
1343                        },
1344                    );
1345                }
1346            }
1347            Self::VminuVx {
1348                vd,
1349                vs2,
1350                rs1: _,
1351                vm,
1352            } => {
1353                if !ext_state.vector_instructions_allowed() {
1354                    ::core::hint::cold_path();
1355                    return Err(ExecutionError::IllegalInstruction {
1356                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1357                    });
1358                }
1359                let Some(vtype) = ext_state.vtype() else {
1360                    ::core::hint::cold_path();
1361                    return Err(ExecutionError::IllegalInstruction {
1362                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1363                    });
1364                };
1365                let group_regs = vtype.vlmul().register_count();
1366                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1367                    program_counter,
1368                    vd,
1369                    group_regs,
1370                )?;
1371                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1372                    program_counter,
1373                    vs2,
1374                    group_regs,
1375                )?;
1376                if !vm && vd == VReg::V0 {
1377                    ::core::hint::cold_path();
1378                    return Err(ExecutionError::IllegalInstruction {
1379                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1380                    });
1381                }
1382                let sew = vtype.vsew();
1383                let scalar = rs1_value.as_i64().cast_unsigned();
1384                // SAFETY: alignment checked above
1385                unsafe {
1386                    zvexx_arith_helpers::execute_arith_op(
1387                        ext_state,
1388                        vd,
1389                        vs2,
1390                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
1391                        vm,
1392                        sew,
1393                        |a, b, sew| {
1394                            let mask = zvexx_arith_helpers::sew_mask(sew);
1395                            if a & mask <= b & mask { a } else { b }
1396                        },
1397                    );
1398                }
1399            }
1400            Self::VminVv { vd, vs2, vs1, vm } => {
1401                if !ext_state.vector_instructions_allowed() {
1402                    ::core::hint::cold_path();
1403                    return Err(ExecutionError::IllegalInstruction {
1404                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1405                    });
1406                }
1407                let Some(vtype) = ext_state.vtype() else {
1408                    ::core::hint::cold_path();
1409                    return Err(ExecutionError::IllegalInstruction {
1410                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1411                    });
1412                };
1413                let group_regs = vtype.vlmul().register_count();
1414                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1415                    program_counter,
1416                    vd,
1417                    group_regs,
1418                )?;
1419                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1420                    program_counter,
1421                    vs2,
1422                    group_regs,
1423                )?;
1424                zvexx_arith_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                let sew = vtype.vsew();
1436                // SAFETY: alignment checked above
1437                unsafe {
1438                    zvexx_arith_helpers::execute_arith_op(
1439                        ext_state,
1440                        vd,
1441                        vs2,
1442                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
1443                        vm,
1444                        sew,
1445                        |a, b, sew| {
1446                            if zvexx_arith_helpers::sign_extend(a, sew)
1447                                <= zvexx_arith_helpers::sign_extend(b, sew)
1448                            {
1449                                a
1450                            } else {
1451                                b
1452                            }
1453                        },
1454                    );
1455                }
1456            }
1457            Self::VminVx {
1458                vd,
1459                vs2,
1460                rs1: _,
1461                vm,
1462            } => {
1463                if !ext_state.vector_instructions_allowed() {
1464                    ::core::hint::cold_path();
1465                    return Err(ExecutionError::IllegalInstruction {
1466                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1467                    });
1468                }
1469                let Some(vtype) = ext_state.vtype() else {
1470                    ::core::hint::cold_path();
1471                    return Err(ExecutionError::IllegalInstruction {
1472                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1473                    });
1474                };
1475                let group_regs = vtype.vlmul().register_count();
1476                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1477                    program_counter,
1478                    vd,
1479                    group_regs,
1480                )?;
1481                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1482                    program_counter,
1483                    vs2,
1484                    group_regs,
1485                )?;
1486                if !vm && vd == VReg::V0 {
1487                    ::core::hint::cold_path();
1488                    return Err(ExecutionError::IllegalInstruction {
1489                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1490                    });
1491                }
1492                let sew = vtype.vsew();
1493                let scalar = rs1_value.as_i64().cast_unsigned();
1494                // SAFETY: alignment checked above
1495                unsafe {
1496                    zvexx_arith_helpers::execute_arith_op(
1497                        ext_state,
1498                        vd,
1499                        vs2,
1500                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
1501                        vm,
1502                        sew,
1503                        |a, b, sew| {
1504                            if zvexx_arith_helpers::sign_extend(a, sew)
1505                                <= zvexx_arith_helpers::sign_extend(b, sew)
1506                            {
1507                                a
1508                            } else {
1509                                b
1510                            }
1511                        },
1512                    );
1513                }
1514            }
1515            // vmaxu / vmax
1516            Self::VmaxuVv { vd, vs2, vs1, vm } => {
1517                if !ext_state.vector_instructions_allowed() {
1518                    ::core::hint::cold_path();
1519                    return Err(ExecutionError::IllegalInstruction {
1520                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1521                    });
1522                }
1523                let Some(vtype) = ext_state.vtype() else {
1524                    ::core::hint::cold_path();
1525                    return Err(ExecutionError::IllegalInstruction {
1526                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1527                    });
1528                };
1529                let group_regs = vtype.vlmul().register_count();
1530                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1531                    program_counter,
1532                    vd,
1533                    group_regs,
1534                )?;
1535                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1536                    program_counter,
1537                    vs2,
1538                    group_regs,
1539                )?;
1540                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1541                    program_counter,
1542                    vs1,
1543                    group_regs,
1544                )?;
1545                if !vm && vd == VReg::V0 {
1546                    ::core::hint::cold_path();
1547                    return Err(ExecutionError::IllegalInstruction {
1548                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1549                    });
1550                }
1551                let sew = vtype.vsew();
1552                // SAFETY: alignment checked above
1553                unsafe {
1554                    zvexx_arith_helpers::execute_arith_op(
1555                        ext_state,
1556                        vd,
1557                        vs2,
1558                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
1559                        vm,
1560                        sew,
1561                        |a, b, sew| {
1562                            let mask = zvexx_arith_helpers::sew_mask(sew);
1563                            if a & mask >= b & mask { a } else { b }
1564                        },
1565                    );
1566                }
1567            }
1568            Self::VmaxuVx {
1569                vd,
1570                vs2,
1571                rs1: _,
1572                vm,
1573            } => {
1574                if !ext_state.vector_instructions_allowed() {
1575                    ::core::hint::cold_path();
1576                    return Err(ExecutionError::IllegalInstruction {
1577                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1578                    });
1579                }
1580                let Some(vtype) = ext_state.vtype() else {
1581                    ::core::hint::cold_path();
1582                    return Err(ExecutionError::IllegalInstruction {
1583                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1584                    });
1585                };
1586                let group_regs = vtype.vlmul().register_count();
1587                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1588                    program_counter,
1589                    vd,
1590                    group_regs,
1591                )?;
1592                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1593                    program_counter,
1594                    vs2,
1595                    group_regs,
1596                )?;
1597                if !vm && vd == VReg::V0 {
1598                    ::core::hint::cold_path();
1599                    return Err(ExecutionError::IllegalInstruction {
1600                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1601                    });
1602                }
1603                let sew = vtype.vsew();
1604                let scalar = rs1_value.as_i64().cast_unsigned();
1605                // SAFETY: alignment checked above
1606                unsafe {
1607                    zvexx_arith_helpers::execute_arith_op(
1608                        ext_state,
1609                        vd,
1610                        vs2,
1611                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
1612                        vm,
1613                        sew,
1614                        |a, b, sew| {
1615                            let mask = zvexx_arith_helpers::sew_mask(sew);
1616                            if a & mask >= b & mask { a } else { b }
1617                        },
1618                    );
1619                }
1620            }
1621            Self::VmaxVv { vd, vs2, vs1, vm } => {
1622                if !ext_state.vector_instructions_allowed() {
1623                    ::core::hint::cold_path();
1624                    return Err(ExecutionError::IllegalInstruction {
1625                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1626                    });
1627                }
1628                let Some(vtype) = ext_state.vtype() else {
1629                    ::core::hint::cold_path();
1630                    return Err(ExecutionError::IllegalInstruction {
1631                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1632                    });
1633                };
1634                let group_regs = vtype.vlmul().register_count();
1635                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1636                    program_counter,
1637                    vd,
1638                    group_regs,
1639                )?;
1640                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1641                    program_counter,
1642                    vs2,
1643                    group_regs,
1644                )?;
1645                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1646                    program_counter,
1647                    vs1,
1648                    group_regs,
1649                )?;
1650                if !vm && vd == VReg::V0 {
1651                    ::core::hint::cold_path();
1652                    return Err(ExecutionError::IllegalInstruction {
1653                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1654                    });
1655                }
1656                let sew = vtype.vsew();
1657                // SAFETY: alignment checked above
1658                unsafe {
1659                    zvexx_arith_helpers::execute_arith_op(
1660                        ext_state,
1661                        vd,
1662                        vs2,
1663                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
1664                        vm,
1665                        sew,
1666                        |a, b, sew| {
1667                            if zvexx_arith_helpers::sign_extend(a, sew)
1668                                >= zvexx_arith_helpers::sign_extend(b, sew)
1669                            {
1670                                a
1671                            } else {
1672                                b
1673                            }
1674                        },
1675                    );
1676                }
1677            }
1678            Self::VmaxVx {
1679                vd,
1680                vs2,
1681                rs1: _,
1682                vm,
1683            } => {
1684                if !ext_state.vector_instructions_allowed() {
1685                    ::core::hint::cold_path();
1686                    return Err(ExecutionError::IllegalInstruction {
1687                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1688                    });
1689                }
1690                let Some(vtype) = ext_state.vtype() else {
1691                    ::core::hint::cold_path();
1692                    return Err(ExecutionError::IllegalInstruction {
1693                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1694                    });
1695                };
1696                let group_regs = vtype.vlmul().register_count();
1697                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1698                    program_counter,
1699                    vd,
1700                    group_regs,
1701                )?;
1702                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1703                    program_counter,
1704                    vs2,
1705                    group_regs,
1706                )?;
1707                if !vm && vd == VReg::V0 {
1708                    ::core::hint::cold_path();
1709                    return Err(ExecutionError::IllegalInstruction {
1710                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1711                    });
1712                }
1713                let sew = vtype.vsew();
1714                let scalar = rs1_value.as_i64().cast_unsigned();
1715                // SAFETY: alignment checked above
1716                unsafe {
1717                    zvexx_arith_helpers::execute_arith_op(
1718                        ext_state,
1719                        vd,
1720                        vs2,
1721                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
1722                        vm,
1723                        sew,
1724                        |a, b, sew| {
1725                            if zvexx_arith_helpers::sign_extend(a, sew)
1726                                >= zvexx_arith_helpers::sign_extend(b, sew)
1727                            {
1728                                a
1729                            } else {
1730                                b
1731                            }
1732                        },
1733                    );
1734                }
1735            }
1736            // vmseq
1737            Self::VmseqVv { vd, vs2, vs1, vm } => {
1738                if !ext_state.vector_instructions_allowed() {
1739                    ::core::hint::cold_path();
1740                    return Err(ExecutionError::IllegalInstruction {
1741                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1742                    });
1743                }
1744                let Some(vtype) = ext_state.vtype() else {
1745                    ::core::hint::cold_path();
1746                    return Err(ExecutionError::IllegalInstruction {
1747                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1748                    });
1749                };
1750                let group_regs = vtype.vlmul().register_count();
1751                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1752                    program_counter,
1753                    vs2,
1754                    group_regs,
1755                )?;
1756                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1757                    program_counter,
1758                    vs1,
1759                    group_regs,
1760                )?;
1761                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
1762                    program_counter,
1763                    vd,
1764                    vs2,
1765                    group_regs,
1766                )?;
1767                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
1768                    program_counter,
1769                    vd,
1770                    vs1,
1771                    group_regs,
1772                )?;
1773                let sew = vtype.vsew();
1774                // SAFETY: `vs2` and `vs1` alignment checked; `vd` is a single mask register,
1775                // no alignment constraint; `vl <= VLMAX <= VLEN` so all element indices fit
1776                // within the mask register. Mask-dest overlap rule (ยง11.8) checked above.
1777                unsafe {
1778                    zvexx_arith_helpers::execute_compare_op(
1779                        ext_state,
1780                        vd,
1781                        vs2,
1782                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
1783                        vm,
1784                        sew,
1785                        |a, b, sew| {
1786                            (a & zvexx_arith_helpers::sew_mask(sew))
1787                                == (b & zvexx_arith_helpers::sew_mask(sew))
1788                        },
1789                    );
1790                }
1791            }
1792            Self::VmseqVx {
1793                vd,
1794                vs2,
1795                rs1: _,
1796                vm,
1797            } => {
1798                if !ext_state.vector_instructions_allowed() {
1799                    ::core::hint::cold_path();
1800                    return Err(ExecutionError::IllegalInstruction {
1801                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1802                    });
1803                }
1804                let Some(vtype) = ext_state.vtype() else {
1805                    ::core::hint::cold_path();
1806                    return Err(ExecutionError::IllegalInstruction {
1807                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1808                    });
1809                };
1810                let group_regs = vtype.vlmul().register_count();
1811                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1812                    program_counter,
1813                    vs2,
1814                    group_regs,
1815                )?;
1816                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
1817                    program_counter,
1818                    vd,
1819                    vs2,
1820                    group_regs,
1821                )?;
1822                let sew = vtype.vsew();
1823                let scalar = rs1_value.as_i64().cast_unsigned();
1824                // SAFETY: see `VmseqVv`
1825                unsafe {
1826                    zvexx_arith_helpers::execute_compare_op(
1827                        ext_state,
1828                        vd,
1829                        vs2,
1830                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
1831                        vm,
1832                        sew,
1833                        |a, b, sew| {
1834                            (a & zvexx_arith_helpers::sew_mask(sew))
1835                                == (b & zvexx_arith_helpers::sew_mask(sew))
1836                        },
1837                    );
1838                }
1839            }
1840            Self::VmseqVi { vd, vs2, imm, vm } => {
1841                if !ext_state.vector_instructions_allowed() {
1842                    ::core::hint::cold_path();
1843                    return Err(ExecutionError::IllegalInstruction {
1844                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1845                    });
1846                }
1847                let Some(vtype) = ext_state.vtype() else {
1848                    ::core::hint::cold_path();
1849                    return Err(ExecutionError::IllegalInstruction {
1850                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1851                    });
1852                };
1853                let group_regs = vtype.vlmul().register_count();
1854                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1855                    program_counter,
1856                    vs2,
1857                    group_regs,
1858                )?;
1859                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
1860                    program_counter,
1861                    vd,
1862                    vs2,
1863                    group_regs,
1864                )?;
1865                let sew = vtype.vsew();
1866                let scalar = i64::from(imm).cast_unsigned();
1867                // SAFETY: see `VmseqVv`
1868                unsafe {
1869                    zvexx_arith_helpers::execute_compare_op(
1870                        ext_state,
1871                        vd,
1872                        vs2,
1873                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
1874                        vm,
1875                        sew,
1876                        |a, b, sew| {
1877                            (a & zvexx_arith_helpers::sew_mask(sew))
1878                                == (b & zvexx_arith_helpers::sew_mask(sew))
1879                        },
1880                    );
1881                }
1882            }
1883            // vmsne
1884            Self::VmsneVv { vd, vs2, vs1, vm } => {
1885                if !ext_state.vector_instructions_allowed() {
1886                    ::core::hint::cold_path();
1887                    return Err(ExecutionError::IllegalInstruction {
1888                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1889                    });
1890                }
1891                let Some(vtype) = ext_state.vtype() else {
1892                    ::core::hint::cold_path();
1893                    return Err(ExecutionError::IllegalInstruction {
1894                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1895                    });
1896                };
1897                let group_regs = vtype.vlmul().register_count();
1898                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1899                    program_counter,
1900                    vs2,
1901                    group_regs,
1902                )?;
1903                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1904                    program_counter,
1905                    vs1,
1906                    group_regs,
1907                )?;
1908                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
1909                    program_counter,
1910                    vd,
1911                    vs2,
1912                    group_regs,
1913                )?;
1914                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
1915                    program_counter,
1916                    vd,
1917                    vs1,
1918                    group_regs,
1919                )?;
1920                let sew = vtype.vsew();
1921                // SAFETY: see `VmseqVv`
1922                unsafe {
1923                    zvexx_arith_helpers::execute_compare_op(
1924                        ext_state,
1925                        vd,
1926                        vs2,
1927                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
1928                        vm,
1929                        sew,
1930                        |a, b, sew| {
1931                            (a & zvexx_arith_helpers::sew_mask(sew))
1932                                != (b & zvexx_arith_helpers::sew_mask(sew))
1933                        },
1934                    );
1935                }
1936            }
1937            Self::VmsneVx {
1938                vd,
1939                vs2,
1940                rs1: _,
1941                vm,
1942            } => {
1943                if !ext_state.vector_instructions_allowed() {
1944                    ::core::hint::cold_path();
1945                    return Err(ExecutionError::IllegalInstruction {
1946                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1947                    });
1948                }
1949                let Some(vtype) = ext_state.vtype() else {
1950                    ::core::hint::cold_path();
1951                    return Err(ExecutionError::IllegalInstruction {
1952                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1953                    });
1954                };
1955                let group_regs = vtype.vlmul().register_count();
1956                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1957                    program_counter,
1958                    vs2,
1959                    group_regs,
1960                )?;
1961                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
1962                    program_counter,
1963                    vd,
1964                    vs2,
1965                    group_regs,
1966                )?;
1967                let sew = vtype.vsew();
1968                let scalar = rs1_value.as_i64().cast_unsigned();
1969                // SAFETY: see `VmseqVv`
1970                unsafe {
1971                    zvexx_arith_helpers::execute_compare_op(
1972                        ext_state,
1973                        vd,
1974                        vs2,
1975                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
1976                        vm,
1977                        sew,
1978                        |a, b, sew| {
1979                            (a & zvexx_arith_helpers::sew_mask(sew))
1980                                != (b & zvexx_arith_helpers::sew_mask(sew))
1981                        },
1982                    );
1983                }
1984            }
1985            Self::VmsneVi { vd, vs2, imm, vm } => {
1986                if !ext_state.vector_instructions_allowed() {
1987                    ::core::hint::cold_path();
1988                    return Err(ExecutionError::IllegalInstruction {
1989                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1990                    });
1991                }
1992                let Some(vtype) = ext_state.vtype() else {
1993                    ::core::hint::cold_path();
1994                    return Err(ExecutionError::IllegalInstruction {
1995                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1996                    });
1997                };
1998                let group_regs = vtype.vlmul().register_count();
1999                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2000                    program_counter,
2001                    vs2,
2002                    group_regs,
2003                )?;
2004                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2005                    program_counter,
2006                    vd,
2007                    vs2,
2008                    group_regs,
2009                )?;
2010                let sew = vtype.vsew();
2011                let scalar = i64::from(imm).cast_unsigned();
2012                // SAFETY: see `VmseqVv`
2013                unsafe {
2014                    zvexx_arith_helpers::execute_compare_op(
2015                        ext_state,
2016                        vd,
2017                        vs2,
2018                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
2019                        vm,
2020                        sew,
2021                        |a, b, sew| {
2022                            (a & zvexx_arith_helpers::sew_mask(sew))
2023                                != (b & zvexx_arith_helpers::sew_mask(sew))
2024                        },
2025                    );
2026                }
2027            }
2028            // vmsltu (unsigned <)
2029            Self::VmsltuVv { vd, vs2, vs1, vm } => {
2030                if !ext_state.vector_instructions_allowed() {
2031                    ::core::hint::cold_path();
2032                    return Err(ExecutionError::IllegalInstruction {
2033                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2034                    });
2035                }
2036                let Some(vtype) = ext_state.vtype() else {
2037                    ::core::hint::cold_path();
2038                    return Err(ExecutionError::IllegalInstruction {
2039                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2040                    });
2041                };
2042                let group_regs = vtype.vlmul().register_count();
2043                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2044                    program_counter,
2045                    vs2,
2046                    group_regs,
2047                )?;
2048                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2049                    program_counter,
2050                    vs1,
2051                    group_regs,
2052                )?;
2053                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2054                    program_counter,
2055                    vd,
2056                    vs2,
2057                    group_regs,
2058                )?;
2059                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2060                    program_counter,
2061                    vd,
2062                    vs1,
2063                    group_regs,
2064                )?;
2065                let sew = vtype.vsew();
2066                // SAFETY: see `VmseqVv`
2067                unsafe {
2068                    zvexx_arith_helpers::execute_compare_op(
2069                        ext_state,
2070                        vd,
2071                        vs2,
2072                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
2073                        vm,
2074                        sew,
2075                        |a, b, sew| {
2076                            (a & zvexx_arith_helpers::sew_mask(sew))
2077                                < (b & zvexx_arith_helpers::sew_mask(sew))
2078                        },
2079                    );
2080                }
2081            }
2082            Self::VmsltuVx {
2083                vd,
2084                vs2,
2085                rs1: _,
2086                vm,
2087            } => {
2088                if !ext_state.vector_instructions_allowed() {
2089                    ::core::hint::cold_path();
2090                    return Err(ExecutionError::IllegalInstruction {
2091                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2092                    });
2093                }
2094                let Some(vtype) = ext_state.vtype() else {
2095                    ::core::hint::cold_path();
2096                    return Err(ExecutionError::IllegalInstruction {
2097                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2098                    });
2099                };
2100                let group_regs = vtype.vlmul().register_count();
2101                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2102                    program_counter,
2103                    vs2,
2104                    group_regs,
2105                )?;
2106                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2107                    program_counter,
2108                    vd,
2109                    vs2,
2110                    group_regs,
2111                )?;
2112                let sew = vtype.vsew();
2113                let scalar = rs1_value.as_i64().cast_unsigned();
2114                // SAFETY: see `VmseqVv`
2115                unsafe {
2116                    zvexx_arith_helpers::execute_compare_op(
2117                        ext_state,
2118                        vd,
2119                        vs2,
2120                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
2121                        vm,
2122                        sew,
2123                        |a, b, sew| {
2124                            (a & zvexx_arith_helpers::sew_mask(sew))
2125                                < (b & zvexx_arith_helpers::sew_mask(sew))
2126                        },
2127                    );
2128                }
2129            }
2130            // vmslt (signed <)
2131            Self::VmsltVv { vd, vs2, vs1, vm } => {
2132                if !ext_state.vector_instructions_allowed() {
2133                    ::core::hint::cold_path();
2134                    return Err(ExecutionError::IllegalInstruction {
2135                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2136                    });
2137                }
2138                let Some(vtype) = ext_state.vtype() else {
2139                    ::core::hint::cold_path();
2140                    return Err(ExecutionError::IllegalInstruction {
2141                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2142                    });
2143                };
2144                let group_regs = vtype.vlmul().register_count();
2145                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2146                    program_counter,
2147                    vs2,
2148                    group_regs,
2149                )?;
2150                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2151                    program_counter,
2152                    vs1,
2153                    group_regs,
2154                )?;
2155                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2156                    program_counter,
2157                    vd,
2158                    vs2,
2159                    group_regs,
2160                )?;
2161                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2162                    program_counter,
2163                    vd,
2164                    vs1,
2165                    group_regs,
2166                )?;
2167                let sew = vtype.vsew();
2168                // SAFETY: see `VmseqVv`
2169                unsafe {
2170                    zvexx_arith_helpers::execute_compare_op(
2171                        ext_state,
2172                        vd,
2173                        vs2,
2174                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
2175                        vm,
2176                        sew,
2177                        |a, b, sew| {
2178                            zvexx_arith_helpers::sign_extend(a, sew)
2179                                < zvexx_arith_helpers::sign_extend(b, sew)
2180                        },
2181                    );
2182                }
2183            }
2184            Self::VmsltVx {
2185                vd,
2186                vs2,
2187                rs1: _,
2188                vm,
2189            } => {
2190                if !ext_state.vector_instructions_allowed() {
2191                    ::core::hint::cold_path();
2192                    return Err(ExecutionError::IllegalInstruction {
2193                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2194                    });
2195                }
2196                let Some(vtype) = ext_state.vtype() else {
2197                    ::core::hint::cold_path();
2198                    return Err(ExecutionError::IllegalInstruction {
2199                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2200                    });
2201                };
2202                let group_regs = vtype.vlmul().register_count();
2203                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2204                    program_counter,
2205                    vs2,
2206                    group_regs,
2207                )?;
2208                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2209                    program_counter,
2210                    vd,
2211                    vs2,
2212                    group_regs,
2213                )?;
2214                let sew = vtype.vsew();
2215                let scalar = rs1_value.as_i64().cast_unsigned();
2216                // SAFETY: see `VmseqVv`
2217                unsafe {
2218                    zvexx_arith_helpers::execute_compare_op(
2219                        ext_state,
2220                        vd,
2221                        vs2,
2222                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
2223                        vm,
2224                        sew,
2225                        |a, b, sew| {
2226                            zvexx_arith_helpers::sign_extend(a, sew)
2227                                < zvexx_arith_helpers::sign_extend(b, sew)
2228                        },
2229                    );
2230                }
2231            }
2232            // vmsleu (unsigned <=)
2233            Self::VmsleuVv { vd, vs2, vs1, vm } => {
2234                if !ext_state.vector_instructions_allowed() {
2235                    ::core::hint::cold_path();
2236                    return Err(ExecutionError::IllegalInstruction {
2237                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2238                    });
2239                }
2240                let Some(vtype) = ext_state.vtype() else {
2241                    ::core::hint::cold_path();
2242                    return Err(ExecutionError::IllegalInstruction {
2243                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2244                    });
2245                };
2246                let group_regs = vtype.vlmul().register_count();
2247                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2248                    program_counter,
2249                    vs2,
2250                    group_regs,
2251                )?;
2252                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2253                    program_counter,
2254                    vs1,
2255                    group_regs,
2256                )?;
2257                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2258                    program_counter,
2259                    vd,
2260                    vs2,
2261                    group_regs,
2262                )?;
2263                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2264                    program_counter,
2265                    vd,
2266                    vs1,
2267                    group_regs,
2268                )?;
2269                let sew = vtype.vsew();
2270                // SAFETY: see `VmseqVv`
2271                unsafe {
2272                    zvexx_arith_helpers::execute_compare_op(
2273                        ext_state,
2274                        vd,
2275                        vs2,
2276                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
2277                        vm,
2278                        sew,
2279                        |a, b, sew| {
2280                            (a & zvexx_arith_helpers::sew_mask(sew))
2281                                <= (b & zvexx_arith_helpers::sew_mask(sew))
2282                        },
2283                    );
2284                }
2285            }
2286            Self::VmsleuVx {
2287                vd,
2288                vs2,
2289                rs1: _,
2290                vm,
2291            } => {
2292                if !ext_state.vector_instructions_allowed() {
2293                    ::core::hint::cold_path();
2294                    return Err(ExecutionError::IllegalInstruction {
2295                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2296                    });
2297                }
2298                let Some(vtype) = ext_state.vtype() else {
2299                    ::core::hint::cold_path();
2300                    return Err(ExecutionError::IllegalInstruction {
2301                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2302                    });
2303                };
2304                let group_regs = vtype.vlmul().register_count();
2305                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2306                    program_counter,
2307                    vs2,
2308                    group_regs,
2309                )?;
2310                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2311                    program_counter,
2312                    vd,
2313                    vs2,
2314                    group_regs,
2315                )?;
2316                let sew = vtype.vsew();
2317                let scalar = rs1_value.as_i64().cast_unsigned();
2318                // SAFETY: see `VmseqVv`
2319                unsafe {
2320                    zvexx_arith_helpers::execute_compare_op(
2321                        ext_state,
2322                        vd,
2323                        vs2,
2324                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
2325                        vm,
2326                        sew,
2327                        |a, b, sew| {
2328                            (a & zvexx_arith_helpers::sew_mask(sew))
2329                                <= (b & zvexx_arith_helpers::sew_mask(sew))
2330                        },
2331                    );
2332                }
2333            }
2334            Self::VmsleuVi { vd, vs2, imm, vm } => {
2335                if !ext_state.vector_instructions_allowed() {
2336                    ::core::hint::cold_path();
2337                    return Err(ExecutionError::IllegalInstruction {
2338                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2339                    });
2340                }
2341                let Some(vtype) = ext_state.vtype() else {
2342                    ::core::hint::cold_path();
2343                    return Err(ExecutionError::IllegalInstruction {
2344                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2345                    });
2346                };
2347                let group_regs = vtype.vlmul().register_count();
2348                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2349                    program_counter,
2350                    vs2,
2351                    group_regs,
2352                )?;
2353                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2354                    program_counter,
2355                    vd,
2356                    vs2,
2357                    group_regs,
2358                )?;
2359                let sew = vtype.vsew();
2360                // Per spec ยง12.8: for vmsleu.vi, the immediate is sign-extended to XLEN
2361                // then the comparison is unsigned. A negative i8 immediate sign-extends to
2362                // a large u64 (e.g. -1 -> 0xFFFF...FF). Both operands are masked to SEW
2363                // before comparing, so the effective immediate is (0xFFFF...FF &
2364                // zve64x_arith_helpers::sew_mask), which equals
2365                // zve64x_arith_helpers::sew_mask (the maximum SEW-wide unsigned value). This means
2366                // vs2[i] <= imm is always true for SEW < XLEN when imm < 0.
2367                let scalar = i64::from(imm).cast_unsigned();
2368                // SAFETY: see `VmseqVv`
2369                unsafe {
2370                    zvexx_arith_helpers::execute_compare_op(
2371                        ext_state,
2372                        vd,
2373                        vs2,
2374                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
2375                        vm,
2376                        sew,
2377                        |a, b, sew| {
2378                            (a & zvexx_arith_helpers::sew_mask(sew))
2379                                <= (b & zvexx_arith_helpers::sew_mask(sew))
2380                        },
2381                    );
2382                }
2383            }
2384            // vmsle (signed <=)
2385            Self::VmsleVv { vd, vs2, vs1, vm } => {
2386                if !ext_state.vector_instructions_allowed() {
2387                    ::core::hint::cold_path();
2388                    return Err(ExecutionError::IllegalInstruction {
2389                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2390                    });
2391                }
2392                let Some(vtype) = ext_state.vtype() else {
2393                    ::core::hint::cold_path();
2394                    return Err(ExecutionError::IllegalInstruction {
2395                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2396                    });
2397                };
2398                let group_regs = vtype.vlmul().register_count();
2399                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2400                    program_counter,
2401                    vs2,
2402                    group_regs,
2403                )?;
2404                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2405                    program_counter,
2406                    vs1,
2407                    group_regs,
2408                )?;
2409                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2410                    program_counter,
2411                    vd,
2412                    vs2,
2413                    group_regs,
2414                )?;
2415                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2416                    program_counter,
2417                    vd,
2418                    vs1,
2419                    group_regs,
2420                )?;
2421                let sew = vtype.vsew();
2422                // SAFETY: see `VmseqVv`
2423                unsafe {
2424                    zvexx_arith_helpers::execute_compare_op(
2425                        ext_state,
2426                        vd,
2427                        vs2,
2428                        zvexx_arith_helpers::OpSrc::Vreg(vs1),
2429                        vm,
2430                        sew,
2431                        |a, b, sew| {
2432                            zvexx_arith_helpers::sign_extend(a, sew)
2433                                <= zvexx_arith_helpers::sign_extend(b, sew)
2434                        },
2435                    );
2436                }
2437            }
2438            Self::VmsleVx {
2439                vd,
2440                vs2,
2441                rs1: _,
2442                vm,
2443            } => {
2444                if !ext_state.vector_instructions_allowed() {
2445                    ::core::hint::cold_path();
2446                    return Err(ExecutionError::IllegalInstruction {
2447                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2448                    });
2449                }
2450                let Some(vtype) = ext_state.vtype() else {
2451                    ::core::hint::cold_path();
2452                    return Err(ExecutionError::IllegalInstruction {
2453                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2454                    });
2455                };
2456                let group_regs = vtype.vlmul().register_count();
2457                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2458                    program_counter,
2459                    vs2,
2460                    group_regs,
2461                )?;
2462                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2463                    program_counter,
2464                    vd,
2465                    vs2,
2466                    group_regs,
2467                )?;
2468                let sew = vtype.vsew();
2469                let scalar = rs1_value.as_i64().cast_unsigned();
2470                // SAFETY: see `VmseqVv`
2471                unsafe {
2472                    zvexx_arith_helpers::execute_compare_op(
2473                        ext_state,
2474                        vd,
2475                        vs2,
2476                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
2477                        vm,
2478                        sew,
2479                        |a, b, sew| {
2480                            zvexx_arith_helpers::sign_extend(a, sew)
2481                                <= zvexx_arith_helpers::sign_extend(b, sew)
2482                        },
2483                    );
2484                }
2485            }
2486            Self::VmsleVi { vd, vs2, imm, vm } => {
2487                if !ext_state.vector_instructions_allowed() {
2488                    ::core::hint::cold_path();
2489                    return Err(ExecutionError::IllegalInstruction {
2490                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2491                    });
2492                }
2493                let Some(vtype) = ext_state.vtype() else {
2494                    ::core::hint::cold_path();
2495                    return Err(ExecutionError::IllegalInstruction {
2496                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2497                    });
2498                };
2499                let group_regs = vtype.vlmul().register_count();
2500                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2501                    program_counter,
2502                    vs2,
2503                    group_regs,
2504                )?;
2505                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2506                    program_counter,
2507                    vd,
2508                    vs2,
2509                    group_regs,
2510                )?;
2511                let sew = vtype.vsew();
2512                let scalar = i64::from(imm).cast_unsigned();
2513                // SAFETY: see `VmseqVv`
2514                unsafe {
2515                    zvexx_arith_helpers::execute_compare_op(
2516                        ext_state,
2517                        vd,
2518                        vs2,
2519                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
2520                        vm,
2521                        sew,
2522                        |a, b, sew| {
2523                            zvexx_arith_helpers::sign_extend(a, sew)
2524                                <= zvexx_arith_helpers::sign_extend(b, sew)
2525                        },
2526                    );
2527                }
2528            }
2529            // vmsgtu (unsigned >): no vv form; vx and vi only
2530            Self::VmsgtuVx {
2531                vd,
2532                vs2,
2533                rs1: _,
2534                vm,
2535            } => {
2536                if !ext_state.vector_instructions_allowed() {
2537                    ::core::hint::cold_path();
2538                    return Err(ExecutionError::IllegalInstruction {
2539                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2540                    });
2541                }
2542                let Some(vtype) = ext_state.vtype() else {
2543                    ::core::hint::cold_path();
2544                    return Err(ExecutionError::IllegalInstruction {
2545                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2546                    });
2547                };
2548                let group_regs = vtype.vlmul().register_count();
2549                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2550                    program_counter,
2551                    vs2,
2552                    group_regs,
2553                )?;
2554                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2555                    program_counter,
2556                    vd,
2557                    vs2,
2558                    group_regs,
2559                )?;
2560                let sew = vtype.vsew();
2561                let scalar = rs1_value.as_i64().cast_unsigned();
2562                // SAFETY: see `VmseqVv`
2563                unsafe {
2564                    zvexx_arith_helpers::execute_compare_op(
2565                        ext_state,
2566                        vd,
2567                        vs2,
2568                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
2569                        vm,
2570                        sew,
2571                        |a, b, sew| {
2572                            (a & zvexx_arith_helpers::sew_mask(sew))
2573                                > (b & zvexx_arith_helpers::sew_mask(sew))
2574                        },
2575                    );
2576                }
2577            }
2578            Self::VmsgtuVi { vd, vs2, imm, vm } => {
2579                if !ext_state.vector_instructions_allowed() {
2580                    ::core::hint::cold_path();
2581                    return Err(ExecutionError::IllegalInstruction {
2582                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2583                    });
2584                }
2585                let Some(vtype) = ext_state.vtype() else {
2586                    ::core::hint::cold_path();
2587                    return Err(ExecutionError::IllegalInstruction {
2588                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2589                    });
2590                };
2591                let group_regs = vtype.vlmul().register_count();
2592                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2593                    program_counter,
2594                    vs2,
2595                    group_regs,
2596                )?;
2597                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2598                    program_counter,
2599                    vd,
2600                    vs2,
2601                    group_regs,
2602                )?;
2603                let sew = vtype.vsew();
2604                let scalar = i64::from(imm).cast_unsigned();
2605                // SAFETY: see `VmseqVv`
2606                unsafe {
2607                    zvexx_arith_helpers::execute_compare_op(
2608                        ext_state,
2609                        vd,
2610                        vs2,
2611                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
2612                        vm,
2613                        sew,
2614                        |a, b, sew| {
2615                            (a & zvexx_arith_helpers::sew_mask(sew))
2616                                > (b & zvexx_arith_helpers::sew_mask(sew))
2617                        },
2618                    );
2619                }
2620            }
2621            // vmsgt (signed >): no vv form; vx and vi only
2622            Self::VmsgtVx {
2623                vd,
2624                vs2,
2625                rs1: _,
2626                vm,
2627            } => {
2628                if !ext_state.vector_instructions_allowed() {
2629                    ::core::hint::cold_path();
2630                    return Err(ExecutionError::IllegalInstruction {
2631                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2632                    });
2633                }
2634                let Some(vtype) = ext_state.vtype() else {
2635                    ::core::hint::cold_path();
2636                    return Err(ExecutionError::IllegalInstruction {
2637                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2638                    });
2639                };
2640                let group_regs = vtype.vlmul().register_count();
2641                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2642                    program_counter,
2643                    vs2,
2644                    group_regs,
2645                )?;
2646                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2647                    program_counter,
2648                    vd,
2649                    vs2,
2650                    group_regs,
2651                )?;
2652                let sew = vtype.vsew();
2653                let scalar = rs1_value.as_i64().cast_unsigned();
2654                // SAFETY: see `VmseqVv`
2655                unsafe {
2656                    zvexx_arith_helpers::execute_compare_op(
2657                        ext_state,
2658                        vd,
2659                        vs2,
2660                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
2661                        vm,
2662                        sew,
2663                        |a, b, sew| {
2664                            zvexx_arith_helpers::sign_extend(a, sew)
2665                                > zvexx_arith_helpers::sign_extend(b, sew)
2666                        },
2667                    );
2668                }
2669            }
2670            Self::VmsgtVi { vd, vs2, imm, vm } => {
2671                if !ext_state.vector_instructions_allowed() {
2672                    ::core::hint::cold_path();
2673                    return Err(ExecutionError::IllegalInstruction {
2674                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2675                    });
2676                }
2677                let Some(vtype) = ext_state.vtype() else {
2678                    ::core::hint::cold_path();
2679                    return Err(ExecutionError::IllegalInstruction {
2680                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2681                    });
2682                };
2683                let group_regs = vtype.vlmul().register_count();
2684                zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2685                    program_counter,
2686                    vs2,
2687                    group_regs,
2688                )?;
2689                zvexx_arith_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
2690                    program_counter,
2691                    vd,
2692                    vs2,
2693                    group_regs,
2694                )?;
2695                let sew = vtype.vsew();
2696                let scalar = i64::from(imm).cast_unsigned();
2697                // SAFETY: see `VmseqVv`
2698                unsafe {
2699                    zvexx_arith_helpers::execute_compare_op(
2700                        ext_state,
2701                        vd,
2702                        vs2,
2703                        zvexx_arith_helpers::OpSrc::Scalar(scalar),
2704                        vm,
2705                        sew,
2706                        |a, b, sew| {
2707                            zvexx_arith_helpers::sign_extend(a, sew)
2708                                > zvexx_arith_helpers::sign_extend(b, sew)
2709                        },
2710                    );
2711                }
2712            }
2713        }
2714
2715        Ok(ControlFlow::Continue(Default::default()))
2716    }
2717}