Skip to main content

ab_riscv_interpreter/v/zvexx/
arith.rs

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