ruprim/reduce/components/instructions/
max.rs1use ruda_kernel::dsl as kernel_dsl;
2use super::{ReduceFamily, ReduceInstruction};
3use crate::reduce::components::{
4 instructions::{Accumulator, AccumulatorFormat, Item, ReduceRequirements, ReduceStep, Value},
5 precision::ReducePrecision,
6};
7use ruda_kernel::dsl::prelude::*;
8
9#[derive(Debug, RudaType, Clone)]
12pub struct Max;
13
14impl ReduceFamily for Max {
15 type Instruction<P: ReducePrecision> = Self;
16 type Config = ();
17}
18
19#[ruda]
20impl<P: ReducePrecision> ReduceInstruction<P> for Max {
21 type SharedAccumulator = SharedMemory<Vector<P::EA, P::SI>>;
22 type Config = ();
23
24 fn requirements(_this: &Self) -> ReduceRequirements {
25 ReduceRequirements { coordinates: false }
26 }
27
28 fn accumulator_format(_this: &Self) -> comptime_type!(AccumulatorFormat) {
29 AccumulatorFormat::Single
30 }
31
32 fn from_config(_config: Self::Config) -> Self {
33 Max {}
34 }
35
36 fn null_input(_this: &Self) -> Vector<P::EI, P::SI> {
37 Vector::empty().fill(P::EI::min_value())
38 }
39
40 fn null_accumulator(_this: &Self) -> Accumulator<P> {
41 Accumulator::<P> {
42 elements: Value::new_single(Vector::empty().fill(P::EA::min_value())),
43 args: Value::new_None(),
44 }
45 }
46
47 fn reduce(
48 _this: &Self,
49 accumulator: &mut Accumulator<P>,
50 item: Item<P>,
51 #[comptime] reduce_step: ReduceStep,
52 ) {
53 let accumulator_item = accumulator.elements.item();
54 let elements = match reduce_step {
55 ReduceStep::Plane => {
56 let candidate_item = Vector::cast_from(plane_max(item.elements));
57 select_many(
58 accumulator_item.greater_than(candidate_item),
59 accumulator_item,
60 candidate_item,
61 )
62 }
63 ReduceStep::Identity => {
64 let item = Vector::cast_from(item.elements);
65 select_many(accumulator_item.greater_than(item), accumulator_item, item)
66 }
67 };
68
69 accumulator.elements.assign(&Value::new_single(elements));
70 }
71
72 fn plane_reduce_inplace(_this: &Self, accumulator: &mut Accumulator<P>) {
73 let acc_item = accumulator.elements.item();
74 let candidate_item = Vector::cast_from(plane_max(acc_item));
75 let max = select_many(
76 acc_item.greater_than(candidate_item),
77 acc_item,
78 candidate_item,
79 );
80 accumulator.elements.assign(&Value::new_single(max));
81 }
82
83 fn fuse_accumulators(_this: &Self, accumulator: &mut Accumulator<P>, other: &Accumulator<P>) {
84 let accumulator_item = accumulator.elements.item();
85 let other_item = other.elements.item();
86
87 accumulator.elements.assign(&Value::new_single(select_many(
88 accumulator_item.greater_than(other_item),
89 accumulator_item,
90 other_item,
91 )));
92 }
93
94 fn to_output_parallel<Out: Numeric>(
95 _this: &Self,
96 accumulator: Accumulator<P>,
97 _shape_axis_reduce: usize,
98 ) -> Value<Out> {
99 let mut max = P::EA::min_value();
100 let accumulator = accumulator.elements.item();
101 #[unroll]
102 for k in 0..accumulator.size() {
103 let candidate = accumulator[k];
104 max = select(candidate > max, candidate, max);
105 }
106 Value::new_single(Out::cast_from(max))
107 }
108
109 fn to_output_perpendicular<Out: Numeric>(
110 _this: &Self,
111 accumulator: Accumulator<P>,
112 _shape_axis_reduce: usize,
113 ) -> Value<Vector<Out, P::SI>> {
114 Value::new_single(Vector::cast_from(accumulator.elements.item()))
115 }
116}