Skip to main content

ab_riscv_interpreter/v/zve64x/
arith.rs

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