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