1#[cfg(test)]
4mod tests;
5pub mod zvexx_reduction_helpers;
6
7use crate::v::vector_registers::VectorRegistersExt;
8use crate::v::zvexx::arith::zvexx_arith_helpers;
9use crate::v::zvexx::zvexx_helpers;
10use crate::{
11 ExecutableInstruction, ExecutableInstructionCsr, ExecutableInstructionOperands, ExecutionError,
12 ExecutionResult, FetchInstructionResult, InstructionFetcher, OpaqueThreadedExecutionResult,
13 PackedAddress, ProgramCounter, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands,
14 ThreadedExecutableInstruction, ThreadedExecutionResult, VirtualMemory,
15};
16use ab_riscv_macros::instruction_execution;
17use ab_riscv_primitives::prelude::*;
18
19#[instruction_execution]
20const impl<Reg> ExecutableInstructionOperands for ZveXxReductionInstruction<Reg> where Reg: Register {}
21
22#[instruction_execution]
23const impl<Reg, Env> ExecutableInstructionCsr<Env> for ZveXxReductionInstruction<Reg> where
24 Reg: Register
25{
26}
27
28#[instruction_execution]
29impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
30 for ZveXxReductionInstruction<Reg>
31where
32 Reg: Register,
33 Regs: RegisterFile<Reg>,
34 Env: VectorRegistersExt<Reg>,
35 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
36 Memory: VirtualMemory,
37 PC: ProgramCounter<Reg::Type, Memory>,
38{
39 #[inline(always)]
40 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
41 fn execute(
42 self,
43 Rs1Rs2OperandValues {
44 rs1_value: _,
45 rs2_value: _,
46 }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
47 _regs: &mut Regs,
48 env: &mut Env,
49 _memory: &mut Memory,
50 program_counter: &mut PC,
51 ) -> ExecutionResult<Self::Reg> {
52 match self {
53 Self::Vredsum { vd, vs2, vs1, vm } => {
54 if !env.vector_instructions_allowed() {
55 ::core::hint::cold_path();
56 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
57 address: PackedAddress::new(
58 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
59 ),
60 });
61 }
62 let Some(vtype) = env.vtype() else {
63 ::core::hint::cold_path();
64 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
65 address: PackedAddress::new(
66 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
67 ),
68 });
69 };
70 if env.vstart() != Vstart::ZERO {
72 ::core::hint::cold_path();
73 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
74 address: PackedAddress::new(
75 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
76 ),
77 });
78 }
79 let group_regs = vtype.vlmul().register_count();
80 zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _>(
81 program_counter,
82 vs2,
83 group_regs,
84 )?;
85 let sew = vtype.vsew();
86 let vl = env.vl();
87 unsafe {
90 zvexx_reduction_helpers::execute_reduce_op(
91 env,
92 vd,
93 vs2,
94 vs1,
95 vm,
96 vl,
97 sew,
98 |acc, elem, _sew| acc.wrapping_add(elem),
99 );
100 }
101 }
102 Self::Vredand { vd, vs2, vs1, vm } => {
103 if !env.vector_instructions_allowed() {
104 ::core::hint::cold_path();
105 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
106 address: PackedAddress::new(
107 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
108 ),
109 });
110 }
111 let Some(vtype) = env.vtype() else {
112 ::core::hint::cold_path();
113 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
114 address: PackedAddress::new(
115 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
116 ),
117 });
118 };
119 if env.vstart() != Vstart::ZERO {
120 ::core::hint::cold_path();
121 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
122 address: PackedAddress::new(
123 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
124 ),
125 });
126 }
127 let group_regs = vtype.vlmul().register_count();
128 zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _>(
129 program_counter,
130 vs2,
131 group_regs,
132 )?;
133 let sew = vtype.vsew();
134 let vl = env.vl();
135 unsafe {
137 zvexx_reduction_helpers::execute_reduce_op(
138 env,
139 vd,
140 vs2,
141 vs1,
142 vm,
143 vl,
144 sew,
145 |acc, elem, _sew| acc & elem,
146 );
147 }
148 }
149 Self::Vredor { vd, vs2, vs1, vm } => {
150 if !env.vector_instructions_allowed() {
151 ::core::hint::cold_path();
152 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
153 address: PackedAddress::new(
154 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
155 ),
156 });
157 }
158 let Some(vtype) = env.vtype() else {
159 ::core::hint::cold_path();
160 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
161 address: PackedAddress::new(
162 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
163 ),
164 });
165 };
166 if env.vstart() != Vstart::ZERO {
167 ::core::hint::cold_path();
168 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
169 address: PackedAddress::new(
170 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
171 ),
172 });
173 }
174 let group_regs = vtype.vlmul().register_count();
175 zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _>(
176 program_counter,
177 vs2,
178 group_regs,
179 )?;
180 let sew = vtype.vsew();
181 let vl = env.vl();
182 unsafe {
184 zvexx_reduction_helpers::execute_reduce_op(
185 env,
186 vd,
187 vs2,
188 vs1,
189 vm,
190 vl,
191 sew,
192 |acc, elem, _sew| acc | elem,
193 );
194 }
195 }
196 Self::Vredxor { vd, vs2, vs1, vm } => {
197 if !env.vector_instructions_allowed() {
198 ::core::hint::cold_path();
199 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
200 address: PackedAddress::new(
201 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
202 ),
203 });
204 }
205 let Some(vtype) = env.vtype() else {
206 ::core::hint::cold_path();
207 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
208 address: PackedAddress::new(
209 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
210 ),
211 });
212 };
213 if env.vstart() != Vstart::ZERO {
214 ::core::hint::cold_path();
215 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
216 address: PackedAddress::new(
217 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
218 ),
219 });
220 }
221 let group_regs = vtype.vlmul().register_count();
222 zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _>(
223 program_counter,
224 vs2,
225 group_regs,
226 )?;
227 let sew = vtype.vsew();
228 let vl = env.vl();
229 unsafe {
231 zvexx_reduction_helpers::execute_reduce_op(
232 env,
233 vd,
234 vs2,
235 vs1,
236 vm,
237 vl,
238 sew,
239 |acc, elem, _sew| acc ^ elem,
240 );
241 }
242 }
243 Self::Vredminu { vd, vs2, vs1, vm } => {
244 if !env.vector_instructions_allowed() {
245 ::core::hint::cold_path();
246 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
247 address: PackedAddress::new(
248 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
249 ),
250 });
251 }
252 let Some(vtype) = env.vtype() else {
253 ::core::hint::cold_path();
254 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
255 address: PackedAddress::new(
256 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
257 ),
258 });
259 };
260 if env.vstart() != Vstart::ZERO {
261 ::core::hint::cold_path();
262 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
263 address: PackedAddress::new(
264 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
265 ),
266 });
267 }
268 let group_regs = vtype.vlmul().register_count();
269 zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _>(
270 program_counter,
271 vs2,
272 group_regs,
273 )?;
274 let sew = vtype.vsew();
275 let vl = env.vl();
276 unsafe {
278 zvexx_reduction_helpers::execute_reduce_op(
279 env,
280 vd,
281 vs2,
282 vs1,
283 vm,
284 vl,
285 sew,
286 |acc, elem, sew| {
287 let mask = zvexx_arith_helpers::sew_mask(sew);
288 if elem & mask < acc & mask { elem } else { acc }
289 },
290 );
291 }
292 }
293 Self::Vredmin { vd, vs2, vs1, vm } => {
294 if !env.vector_instructions_allowed() {
295 ::core::hint::cold_path();
296 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
297 address: PackedAddress::new(
298 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
299 ),
300 });
301 }
302 let Some(vtype) = env.vtype() else {
303 ::core::hint::cold_path();
304 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
305 address: PackedAddress::new(
306 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
307 ),
308 });
309 };
310 if env.vstart() != Vstart::ZERO {
311 ::core::hint::cold_path();
312 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
313 address: PackedAddress::new(
314 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
315 ),
316 });
317 }
318 let group_regs = vtype.vlmul().register_count();
319 zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _>(
320 program_counter,
321 vs2,
322 group_regs,
323 )?;
324 let sew = vtype.vsew();
325 let vl = env.vl();
326 unsafe {
328 zvexx_reduction_helpers::execute_reduce_op(
329 env,
330 vd,
331 vs2,
332 vs1,
333 vm,
334 vl,
335 sew,
336 |acc, elem, sew| {
337 if zvexx_arith_helpers::sign_extend(elem, sew)
338 < zvexx_arith_helpers::sign_extend(acc, sew)
339 {
340 elem
341 } else {
342 acc
343 }
344 },
345 );
346 }
347 }
348 Self::Vredmaxu { vd, vs2, vs1, vm } => {
349 if !env.vector_instructions_allowed() {
350 ::core::hint::cold_path();
351 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
352 address: PackedAddress::new(
353 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
354 ),
355 });
356 }
357 let Some(vtype) = env.vtype() else {
358 ::core::hint::cold_path();
359 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
360 address: PackedAddress::new(
361 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
362 ),
363 });
364 };
365 if env.vstart() != Vstart::ZERO {
366 ::core::hint::cold_path();
367 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
368 address: PackedAddress::new(
369 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
370 ),
371 });
372 }
373 let group_regs = vtype.vlmul().register_count();
374 zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _>(
375 program_counter,
376 vs2,
377 group_regs,
378 )?;
379 let sew = vtype.vsew();
380 let vl = env.vl();
381 unsafe {
383 zvexx_reduction_helpers::execute_reduce_op(
384 env,
385 vd,
386 vs2,
387 vs1,
388 vm,
389 vl,
390 sew,
391 |acc, elem, sew| {
392 let mask = zvexx_arith_helpers::sew_mask(sew);
393 if elem & mask > acc & mask { elem } else { acc }
394 },
395 );
396 }
397 }
398 Self::Vredmax { vd, vs2, vs1, vm } => {
399 if !env.vector_instructions_allowed() {
400 ::core::hint::cold_path();
401 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
402 address: PackedAddress::new(
403 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
404 ),
405 });
406 }
407 let Some(vtype) = env.vtype() else {
408 ::core::hint::cold_path();
409 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
410 address: PackedAddress::new(
411 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
412 ),
413 });
414 };
415 if env.vstart() != Vstart::ZERO {
416 ::core::hint::cold_path();
417 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
418 address: PackedAddress::new(
419 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
420 ),
421 });
422 }
423 let group_regs = vtype.vlmul().register_count();
424 zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _>(
425 program_counter,
426 vs2,
427 group_regs,
428 )?;
429 let sew = vtype.vsew();
430 let vl = env.vl();
431 unsafe {
433 zvexx_reduction_helpers::execute_reduce_op(
434 env,
435 vd,
436 vs2,
437 vs1,
438 vm,
439 vl,
440 sew,
441 |acc, elem, sew| {
442 if zvexx_arith_helpers::sign_extend(elem, sew)
443 > zvexx_arith_helpers::sign_extend(acc, sew)
444 {
445 elem
446 } else {
447 acc
448 }
449 },
450 );
451 }
452 }
453 Self::Vwredsumu { vd, vs2, vs1, vm } => {
454 if !env.vector_instructions_allowed() {
455 ::core::hint::cold_path();
456 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
457 address: PackedAddress::new(
458 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
459 ),
460 });
461 }
462 let Some(vtype) = env.vtype() else {
463 ::core::hint::cold_path();
464 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
465 address: PackedAddress::new(
466 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
467 ),
468 });
469 };
470 if env.vstart() != Vstart::ZERO {
471 ::core::hint::cold_path();
472 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
473 address: PackedAddress::new(
474 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
475 ),
476 });
477 }
478 if u32::from(vtype.vsew().bits_width()) * 2 > u32::from(Env::ELEN) {
480 ::core::hint::cold_path();
481 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
482 address: PackedAddress::new(
483 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
484 ),
485 });
486 }
487 let group_regs = vtype.vlmul().register_count();
488 zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _>(
489 program_counter,
490 vs2,
491 group_regs,
492 )?;
493 let sew = vtype.vsew();
494 let vl = env.vl();
495 unsafe {
498 zvexx_reduction_helpers::execute_widening_reduce_op::<false, _, _, _>(
499 env,
500 vd,
501 vs2,
502 vs1,
503 vm,
504 vl,
505 sew,
506 |acc, elem, _sew| acc.wrapping_add(elem),
508 );
509 }
510 }
511 Self::Vwredsum { vd, vs2, vs1, vm } => {
512 if !env.vector_instructions_allowed() {
513 ::core::hint::cold_path();
514 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
515 address: PackedAddress::new(
516 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
517 ),
518 });
519 }
520 let Some(vtype) = env.vtype() else {
521 ::core::hint::cold_path();
522 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
523 address: PackedAddress::new(
524 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
525 ),
526 });
527 };
528 if env.vstart() != Vstart::ZERO {
529 ::core::hint::cold_path();
530 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
531 address: PackedAddress::new(
532 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
533 ),
534 });
535 }
536 if u32::from(vtype.vsew().bits_width()) * 2 > u32::from(Env::ELEN) {
537 ::core::hint::cold_path();
538 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
539 address: PackedAddress::new(
540 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
541 ),
542 });
543 }
544 let group_regs = vtype.vlmul().register_count();
545 zvexx_arith_helpers::check_vreg_group_alignment::<Reg, _, _>(
546 program_counter,
547 vs2,
548 group_regs,
549 )?;
550 let sew = vtype.vsew();
551 let vl = env.vl();
552 unsafe {
554 zvexx_reduction_helpers::execute_widening_reduce_op::<true, _, _, _>(
555 env,
556 vd,
557 vs2,
558 vs1,
559 vm,
560 vl,
561 sew,
562 |acc, elem, _sew| acc.wrapping_add(elem),
564 );
565 }
566 }
567 }
568
569 ExecutionResult::ContinueNoWrite
570 }
571}