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, Hart> ExecutableInstructionOperands for ZveXxReductionInstruction<Hart>
21where
22 Reg: Register,
23 Hart: VectorHartConfig<Reg = Reg>,
24{
25}
26
27#[instruction_execution]
28const impl<Reg, Hart, Env> ExecutableInstructionCsr<Env> for ZveXxReductionInstruction<Hart>
29where
30 Reg: Register,
31 Hart: VectorHartConfig<Reg = Reg>,
32{
33}
34
35#[instruction_execution]
36impl<Reg, Hart, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
37 for ZveXxReductionInstruction<Hart>
38where
39 Reg: Register,
40 Hart: VectorHartConfig<Reg = Reg>,
41 Regs: RegisterFile<Reg>,
42 Env: VectorRegistersExt<Hart = Hart>,
43 Memory: VirtualMemory,
44 PC: ProgramCounter<Reg::Type, Memory>,
45{
46 #[inline(always)]
47 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
48 fn execute(
49 self,
50 Rs1Rs2OperandValues {
51 rs1_value: _,
52 rs2_value: _,
53 }: Rs1Rs2OperandValues<Reg::Type>,
54 _regs: &mut Regs,
55 env: &mut Env,
56 _memory: &mut Memory,
57 program_counter: &PC,
58 ) -> ExecutionResult<Reg> {
59 match self {
60 Self::Vredsum { vd, vs2, vs1, vm } => {
61 if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
62 ::core::hint::cold_path();
63 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
64 address: PackedAddress::new(
65 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
66 ),
67 });
68 }
69 let Some(config) = env.vector_config() else {
70 ::core::hint::cold_path();
71 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
72 address: PackedAddress::new(
73 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
74 ),
75 });
76 };
77 let sew = config.vtype().vsew();
78 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
79 program_counter,
80 config,
81 vs2,
82 sew.as_eew(),
83 )?;
84 zvexx_reduction_helpers::execute_reduce_op(
85 env,
86 vd,
87 vs2,
88 vs1,
89 vm,
90 sew,
91 |acc, elem, _sew| acc.wrapping_add(elem),
92 );
93 }
94 Self::Vredand { vd, vs2, vs1, vm } => {
95 if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
96 ::core::hint::cold_path();
97 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
98 address: PackedAddress::new(
99 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
100 ),
101 });
102 }
103 let Some(config) = env.vector_config() else {
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 sew = config.vtype().vsew();
112 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
113 program_counter,
114 config,
115 vs2,
116 sew.as_eew(),
117 )?;
118 zvexx_reduction_helpers::execute_reduce_op(
119 env,
120 vd,
121 vs2,
122 vs1,
123 vm,
124 sew,
125 |acc, elem, _sew| acc & elem,
126 );
127 }
128 Self::Vredor { vd, vs2, vs1, vm } => {
129 if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
130 ::core::hint::cold_path();
131 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
132 address: PackedAddress::new(
133 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
134 ),
135 });
136 }
137 let Some(config) = env.vector_config() else {
138 ::core::hint::cold_path();
139 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
140 address: PackedAddress::new(
141 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
142 ),
143 });
144 };
145 let sew = config.vtype().vsew();
146 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
147 program_counter,
148 config,
149 vs2,
150 sew.as_eew(),
151 )?;
152 zvexx_reduction_helpers::execute_reduce_op(
153 env,
154 vd,
155 vs2,
156 vs1,
157 vm,
158 sew,
159 |acc, elem, _sew| acc | elem,
160 );
161 }
162 Self::Vredxor { vd, vs2, vs1, vm } => {
163 if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
164 ::core::hint::cold_path();
165 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
166 address: PackedAddress::new(
167 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
168 ),
169 });
170 }
171 let Some(config) = env.vector_config() else {
172 ::core::hint::cold_path();
173 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
174 address: PackedAddress::new(
175 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
176 ),
177 });
178 };
179 let sew = config.vtype().vsew();
180 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
181 program_counter,
182 config,
183 vs2,
184 sew.as_eew(),
185 )?;
186 zvexx_reduction_helpers::execute_reduce_op(
187 env,
188 vd,
189 vs2,
190 vs1,
191 vm,
192 sew,
193 |acc, elem, _sew| acc ^ elem,
194 );
195 }
196 Self::Vredminu { vd, vs2, vs1, vm } => {
197 if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
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(config) = env.vector_config() 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 let sew = config.vtype().vsew();
214 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
215 program_counter,
216 config,
217 vs2,
218 sew.as_eew(),
219 )?;
220 zvexx_reduction_helpers::execute_reduce_op(
221 env,
222 vd,
223 vs2,
224 vs1,
225 vm,
226 sew,
227 |acc, elem, sew| {
228 let mask = zvexx_arith_helpers::sew_mask(sew);
229 if elem & mask < acc & mask { elem } else { acc }
230 },
231 );
232 }
233 Self::Vredmin { vd, vs2, vs1, vm } => {
234 if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
235 ::core::hint::cold_path();
236 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
237 address: PackedAddress::new(
238 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
239 ),
240 });
241 }
242 let Some(config) = env.vector_config() else {
243 ::core::hint::cold_path();
244 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
245 address: PackedAddress::new(
246 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
247 ),
248 });
249 };
250 let sew = config.vtype().vsew();
251 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
252 program_counter,
253 config,
254 vs2,
255 sew.as_eew(),
256 )?;
257 zvexx_reduction_helpers::execute_reduce_op(
258 env,
259 vd,
260 vs2,
261 vs1,
262 vm,
263 sew,
264 |acc, elem, sew| {
265 if zvexx_arith_helpers::sign_extend(elem, sew)
266 < zvexx_arith_helpers::sign_extend(acc, sew)
267 {
268 elem
269 } else {
270 acc
271 }
272 },
273 );
274 }
275 Self::Vredmaxu { vd, vs2, vs1, vm } => {
276 if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
277 ::core::hint::cold_path();
278 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
279 address: PackedAddress::new(
280 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
281 ),
282 });
283 }
284 let Some(config) = env.vector_config() else {
285 ::core::hint::cold_path();
286 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
287 address: PackedAddress::new(
288 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
289 ),
290 });
291 };
292 let sew = config.vtype().vsew();
293 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
294 program_counter,
295 config,
296 vs2,
297 sew.as_eew(),
298 )?;
299 zvexx_reduction_helpers::execute_reduce_op(
300 env,
301 vd,
302 vs2,
303 vs1,
304 vm,
305 sew,
306 |acc, elem, sew| {
307 let mask = zvexx_arith_helpers::sew_mask(sew);
308 if elem & mask > acc & mask { elem } else { acc }
309 },
310 );
311 }
312 Self::Vredmax { vd, vs2, vs1, vm } => {
313 if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
314 ::core::hint::cold_path();
315 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
316 address: PackedAddress::new(
317 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
318 ),
319 });
320 }
321 let Some(config) = env.vector_config() else {
322 ::core::hint::cold_path();
323 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
324 address: PackedAddress::new(
325 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
326 ),
327 });
328 };
329 let sew = config.vtype().vsew();
330 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
331 program_counter,
332 config,
333 vs2,
334 sew.as_eew(),
335 )?;
336 zvexx_reduction_helpers::execute_reduce_op(
337 env,
338 vd,
339 vs2,
340 vs1,
341 vm,
342 sew,
343 |acc, elem, sew| {
344 if zvexx_arith_helpers::sign_extend(elem, sew)
345 > zvexx_arith_helpers::sign_extend(acc, sew)
346 {
347 elem
348 } else {
349 acc
350 }
351 },
352 );
353 }
354 Self::Vwredsumu { vd, vs2, vs1, vm } => {
355 if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
356 ::core::hint::cold_path();
357 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
358 address: PackedAddress::new(
359 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
360 ),
361 });
362 }
363 let Some(config) = env.vector_config() else {
364 ::core::hint::cold_path();
365 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
366 address: PackedAddress::new(
367 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
368 ),
369 });
370 };
371 let Some(widening_sew) =
372 zvexx_helpers::WideningSew::<Env::Hart>::new(config.vtype().vsew())
373 else {
374 ::core::hint::cold_path();
375 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
376 address: PackedAddress::new(
377 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
378 ),
379 });
380 };
381 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
382 program_counter,
383 config,
384 vs2,
385 widening_sew.narrow().as_eew(),
386 )?;
387 zvexx_helpers::check_register_outside_group::<Reg, Env, _, _>(
389 program_counter,
390 vs2,
391 vs1,
392 )?;
393 zvexx_reduction_helpers::execute_widening_reduce_op::<false, _, _, _>(
394 env,
395 vd,
396 vs2,
397 vs1,
398 vm,
399 widening_sew,
400 |acc, elem, _sew| acc.wrapping_add(elem),
402 );
403 }
404 Self::Vwredsum { vd, vs2, vs1, vm } => {
405 if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
406 ::core::hint::cold_path();
407 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
408 address: PackedAddress::new(
409 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
410 ),
411 });
412 }
413 let Some(config) = env.vector_config() else {
414 ::core::hint::cold_path();
415 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
416 address: PackedAddress::new(
417 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
418 ),
419 });
420 };
421 let Some(widening_sew) =
422 zvexx_helpers::WideningSew::<Env::Hart>::new(config.vtype().vsew())
423 else {
424 ::core::hint::cold_path();
425 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
426 address: PackedAddress::new(
427 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
428 ),
429 });
430 };
431 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
432 program_counter,
433 config,
434 vs2,
435 widening_sew.narrow().as_eew(),
436 )?;
437 zvexx_helpers::check_register_outside_group::<Reg, Env, _, _>(
439 program_counter,
440 vs2,
441 vs1,
442 )?;
443 zvexx_reduction_helpers::execute_widening_reduce_op::<true, _, _, _>(
444 env,
445 vd,
446 vs2,
447 vs1,
448 vm,
449 widening_sew,
450 |acc, elem, _sew| acc.wrapping_add(elem),
452 );
453 }
454 }
455
456 ExecutionResult::ContinueNoWrite
457 }
458}