1use cubecl_ir::{
2 CoopMma, Instruction, Marker, Metadata, NonSemantic, Operation, OperationReflect, Operator,
3 TensorIndexingOps, TmaOps, Value, ValueKind,
4};
5
6use crate::{
7 ControlFlow, Function, GlobalState, MemoryBlock, analyses::pointer_source::PointerSource,
8};
9
10impl Function {
11 pub fn visit_out(
12 &mut self,
13 val: &mut Option<Value>,
14 mut visit_write: impl FnMut(&mut Self, &mut Value),
15 ) {
16 if let Some(out) = val {
17 visit_write(self, out);
18 }
19 }
20
21 pub fn visit_instruction_memory_writes(
23 &mut self,
24 state: &GlobalState,
25 inst: &Instruction,
26 mut visit_write: impl FnMut(&mut Self, &MemoryBlock),
27 ) {
28 let pointer_source = self.analysis::<PointerSource>(state);
29 for ptr in inst.operation.write_pointers() {
30 if let Some(source) = pointer_source.borrow_mut().get_mut(&ptr.id()) {
31 visit_write(self, source);
32 }
33 }
34
35 if let Some(Value {
36 kind: ValueKind::Value { id },
37 ..
38 }) = inst.out
39 && let Some(source) = pointer_source.borrow_mut().get_mut(&id)
40 {
41 visit_write(self, source);
42 }
43 }
44
45 pub fn visit_instruction_memory_reads(
46 &mut self,
47 state: &GlobalState,
48 inst: &Instruction,
49 mut visit_read: impl FnMut(&mut Self, &MemoryBlock),
50 ) {
51 let pointer_source = self.analysis::<PointerSource>(state);
52 for ptr in inst.operation.read_pointers() {
53 if let Some(source) = pointer_source.borrow_mut().get_mut(&ptr.id()) {
54 visit_read(self, source);
55 }
56 }
57 }
58
59 pub fn visit_instruction(
62 &mut self,
63 state: &GlobalState,
64 inst: &mut Instruction,
65 visit_read: impl FnMut(&mut Self, &mut Value),
66 visit_write: impl FnMut(&mut Self, &mut Value),
67 ) {
68 self.visit_operation(state, &mut inst.operation, visit_read);
69 self.visit_out(&mut inst.out, visit_write);
70 }
71
72 pub fn visit_operation(
75 &mut self,
76 state: &GlobalState,
77 op: &mut Operation,
78 mut visit_read: impl FnMut(&mut Self, &mut Value),
79 ) {
80 match op {
81 Operation::Marker(Marker::Free(_)) => {}
82 Operation::Metadata(meta) => self.visit_meta(meta, visit_read),
83 Operation::CoopMma(coop_mma) => self.visit_cmma(state, coop_mma, visit_read),
84 Operation::Branch(_) => unreachable!(),
85 Operation::Tma(tma_ops) => self.visit_tma(tma_ops, visit_read),
86 Operation::TensorIndexing(tensor_ops) => self.visit_tensor_ops(tensor_ops, visit_read),
87 Operation::NonSemantic(non_semantic) => {
88 self.visit_nonsemantic(non_semantic, visit_read)
89 }
90 Operation::Operator(Operator::ReadBuiltin(_)) => {}
91 Operation::DeclareVariable { .. } => {}
92 op => {
93 if let Some(args) = op.args_mut() {
94 for arg in args {
95 visit_read(self, arg);
96 }
97 } else {
98 panic!("Found op {op} which doesn't reflect. Needs special handling.");
99 }
100 }
101 }
102 }
103
104 pub fn visit_control_flow(
107 &mut self,
108 op: &mut ControlFlow,
109 mut visit_read: impl FnMut(&mut Self, &mut Value),
110 ) {
111 match op {
112 ControlFlow::IfElse { cond, .. } => visit_read(self, cond),
113 ControlFlow::Switch { value, .. } => visit_read(self, value),
114 ControlFlow::Loop { .. } => {}
115 ControlFlow::LoopBreak { break_cond, .. } => visit_read(self, break_cond),
116 ControlFlow::Return { value } => {
117 if let Some(value) = value {
118 visit_read(self, value);
119 }
120 }
121 ControlFlow::Unreachable | ControlFlow::None => {}
122 }
123 }
124
125 fn visit_meta(
126 &mut self,
127 metadata: &mut Metadata,
128 mut visit_read: impl FnMut(&mut Self, &mut Value),
129 ) {
130 match metadata {
132 Metadata::BufferLength { .. } => {}
133 Metadata::Stride { dim, .. } => {
134 visit_read(self, dim);
135 }
136 Metadata::Shape { dim, .. } => {
137 visit_read(self, dim);
138 }
139 }
140 }
141
142 fn visit_cmma(
143 &mut self,
144 state: &GlobalState,
145 cmma: &mut CoopMma,
146 mut visit_read: impl FnMut(&mut Self, &mut Value),
147 ) {
148 match cmma {
149 CoopMma::Fill { value } => {
150 visit_read(self, value);
151 }
152 CoopMma::Load {
153 ptr,
154 stride,
155 layout: _,
156 } => {
157 visit_read(self, ptr);
158 visit_read(self, stride);
159 }
160 CoopMma::LoadTensor {
161 buffer,
162 layout,
163 view,
164 } => {
165 visit_read(self, buffer);
166 visit_read(self, layout);
167 if let Some(view) = view {
168 visit_read(self, view);
169 }
170 }
171 CoopMma::Execute {
172 mat_a,
173 mat_b,
174 mat_c,
175 } => {
176 visit_read(self, mat_a);
177 visit_read(self, mat_b);
178 visit_read(self, mat_c);
179 }
180 CoopMma::Store {
181 mat,
182 stride,
183 destination,
184 layout: _,
185 } => {
186 visit_read(self, mat);
187 visit_read(self, stride);
188 visit_read(self, destination);
189 }
190 CoopMma::StoreTensor { mat, layout, view } => {
191 visit_read(self, mat);
192 visit_read(self, layout);
193 if let Some(view) = view {
194 visit_read(self, view);
195 }
196 }
197 CoopMma::Cast { input } => {
198 visit_read(self, input);
199 }
200 CoopMma::RowIndex { lane_id, i, .. } => {
201 visit_read(self, lane_id);
202 visit_read(self, i);
203 }
204 CoopMma::ColIndex { lane_id, i, .. } => {
205 visit_read(self, lane_id);
206 visit_read(self, i);
207 }
208 CoopMma::LoadMatrix { ptr, .. } => {
209 visit_read(self, ptr);
210 }
211 CoopMma::StoreMatrix { registers, .. } => {
212 visit_read(self, registers);
213 }
214 CoopMma::ExecuteManual {
215 registers_a,
216 registers_b,
217 registers_c,
218 ..
219 } => {
220 visit_read(self, registers_a);
221 visit_read(self, registers_b);
222 visit_read(self, registers_c);
223 }
224 CoopMma::ExecuteScaled {
225 registers_a,
226 registers_b,
227 registers_c,
228 scales_a,
229 scales_b,
230 ..
231 } => {
232 visit_read(self, registers_a);
233 visit_read(self, registers_b);
234 visit_read(self, registers_c);
235 visit_read(self, scales_a);
236 visit_read(self, scales_b);
237 }
238 CoopMma::ExecuteElementwise { matrix, op } => {
239 visit_read(self, matrix);
240 let func = &state.extra_functions[op];
241 for mut capture in func.implicit_params.clone() {
242 visit_read(self, &mut capture)
243 }
244 }
245 }
246 }
247
248 fn visit_tma(
249 &mut self,
250 tma_ops: &mut TmaOps,
251 mut visit_read: impl FnMut(&mut Self, &mut Value),
252 ) {
253 match tma_ops {
254 TmaOps::TmaStore {
255 source,
256 coordinates,
257 } => {
258 visit_read(self, source);
259 for coord in coordinates {
260 visit_read(self, coord)
261 }
262 }
263 TmaOps::CommitGroup | TmaOps::WaitGroup { .. } | TmaOps::WaitGroupRead { .. } => {}
264 }
265 }
266
267 fn visit_tensor_ops(
268 &mut self,
269 tensor_ops: &mut TensorIndexingOps,
270 mut visit_read: impl FnMut(&mut Self, &mut Value),
271 ) {
272 match tensor_ops {
273 TensorIndexingOps::CreateLayout {
274 shape,
275 strides,
276 clamp_mode: _,
277 } => {
278 for s in shape {
279 visit_read(self, s);
280 }
281 for s in strides.iter_mut().flatten() {
282 visit_read(self, s);
283 }
284 }
285 TensorIndexingOps::CreateView => {}
286 TensorIndexingOps::Slice {
287 layout,
288 offsets,
289 shape,
290 } => {
291 visit_read(self, layout);
292 for o in offsets {
293 visit_read(self, o);
294 }
295 for s in shape {
296 visit_read(self, s);
297 }
298 }
299 }
300 }
301
302 fn visit_nonsemantic(
303 &mut self,
304 non_semantic: &mut NonSemantic,
305 mut visit_read: impl FnMut(&mut Self, &mut Value),
306 ) {
307 match non_semantic {
308 NonSemantic::Comment { .. }
309 | NonSemantic::EnterDebugScope
310 | NonSemantic::ExitDebugScope => {}
311 NonSemantic::Print { args, .. } => {
312 for arg in args {
313 visit_read(self, arg);
314 }
315 }
316 }
317 }
318}