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