xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/r300/compiler/radeon_dataflow.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2009 Nicolai Haehnle.
3  * Copyright 2010 Tom Stellard <[email protected]>
4  * SPDX-License-Identifier: MIT
5  */
6 
7 #include "radeon_dataflow.h"
8 
9 #include "radeon_compiler.h"
10 #include "radeon_compiler_util.h"
11 #include "radeon_program.h"
12 
13 struct read_write_mask_data {
14 	void * UserData;
15 	rc_read_write_mask_fn Cb;
16 };
17 
reads_normal_callback(void * userdata,struct rc_instruction * fullinst,struct rc_src_register * src)18 static void reads_normal_callback(
19 	void * userdata,
20 	struct rc_instruction * fullinst,
21 	struct rc_src_register * src)
22 {
23 	struct read_write_mask_data * cb_data = userdata;
24 	unsigned int refmask = 0;
25 	unsigned int chan;
26 	for(chan = 0; chan < 4; chan++) {
27 		refmask |= 1 << GET_SWZ(src->Swizzle, chan);
28 	}
29 	refmask &= RC_MASK_XYZW;
30 
31 	if (refmask) {
32 		cb_data->Cb(cb_data->UserData, fullinst, src->File,
33 							src->Index, refmask);
34 	}
35 
36 	if (refmask && src->RelAddr) {
37 		cb_data->Cb(cb_data->UserData, fullinst, RC_FILE_ADDRESS, 0,
38 								RC_MASK_X);
39 	}
40 }
41 
pair_get_src_refmasks(unsigned int * refmasks,struct rc_pair_instruction * inst,unsigned int swz,unsigned int src)42 static void pair_get_src_refmasks(unsigned int * refmasks,
43 					struct rc_pair_instruction * inst,
44 					unsigned int swz, unsigned int src)
45 {
46 	if (swz >= 4)
47 		return;
48 
49 	if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y || swz == RC_SWIZZLE_Z) {
50 		if(src == RC_PAIR_PRESUB_SRC) {
51 			unsigned int i;
52 			int srcp_regs =
53 				rc_presubtract_src_reg_count(
54 				inst->RGB.Src[src].Index);
55 			for(i = 0; i < srcp_regs; i++) {
56 				refmasks[i] |= 1 << swz;
57 			}
58 		}
59 		else {
60 			refmasks[src] |= 1 << swz;
61 		}
62 	}
63 
64 	if (swz == RC_SWIZZLE_W) {
65 		if (src == RC_PAIR_PRESUB_SRC) {
66 			unsigned int i;
67 			int srcp_regs = rc_presubtract_src_reg_count(
68 					inst->Alpha.Src[src].Index);
69 			for(i = 0; i < srcp_regs; i++) {
70 				refmasks[i] |= 1 << swz;
71 			}
72 		}
73 		else {
74 			refmasks[src] |= 1 << swz;
75 		}
76 	}
77 }
78 
reads_pair(struct rc_instruction * fullinst,rc_read_write_mask_fn cb,void * userdata)79 static void reads_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
80 {
81 	struct rc_pair_instruction * inst = &fullinst->U.P;
82 	unsigned int refmasks[3] = { 0, 0, 0 };
83 
84 	unsigned int arg;
85 
86 	for(arg = 0; arg < 3; ++arg) {
87 		unsigned int chan;
88 		for(chan = 0; chan < 3; ++chan) {
89 			unsigned int swz_rgb =
90 				GET_SWZ(inst->RGB.Arg[arg].Swizzle, chan);
91 			unsigned int swz_alpha =
92 				GET_SWZ(inst->Alpha.Arg[arg].Swizzle, chan);
93 			pair_get_src_refmasks(refmasks, inst, swz_rgb,
94 						inst->RGB.Arg[arg].Source);
95 			pair_get_src_refmasks(refmasks, inst, swz_alpha,
96 						inst->Alpha.Arg[arg].Source);
97 		}
98 	}
99 
100 	for(unsigned int src = 0; src < 3; ++src) {
101 		if (inst->RGB.Src[src].Used && (refmasks[src] & RC_MASK_XYZ))
102 			cb(userdata, fullinst, inst->RGB.Src[src].File, inst->RGB.Src[src].Index,
103 			   refmasks[src] & RC_MASK_XYZ);
104 
105 		if (inst->Alpha.Src[src].Used && (refmasks[src] & RC_MASK_W))
106 			cb(userdata, fullinst, inst->Alpha.Src[src].File, inst->Alpha.Src[src].Index, RC_MASK_W);
107 	}
108 }
109 
pair_sub_for_all_args(struct rc_instruction * fullinst,struct rc_pair_sub_instruction * sub,rc_pair_read_arg_fn cb,void * userdata)110 static void pair_sub_for_all_args(
111 	struct rc_instruction * fullinst,
112 	struct rc_pair_sub_instruction * sub,
113 	rc_pair_read_arg_fn cb,
114 	void * userdata)
115 {
116 	int i;
117 	const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode);
118 
119 	for(i = 0; i < info->NumSrcRegs; i++) {
120 		unsigned int src_type;
121 
122 		src_type = rc_source_type_swz(sub->Arg[i].Swizzle);
123 
124 		if (src_type == RC_SOURCE_NONE)
125 			continue;
126 
127 		if (sub->Arg[i].Source == RC_PAIR_PRESUB_SRC) {
128 			unsigned int presub_type;
129 			unsigned int presub_src_count;
130 			struct rc_pair_instruction_source * src_array;
131 			unsigned int j;
132 
133 			if (src_type & RC_SOURCE_RGB) {
134 				presub_type = fullinst->
135 					U.P.RGB.Src[RC_PAIR_PRESUB_SRC].Index;
136 				src_array = fullinst->U.P.RGB.Src;
137 			} else {
138 				presub_type = fullinst->
139 					U.P.Alpha.Src[RC_PAIR_PRESUB_SRC].Index;
140 				src_array = fullinst->U.P.Alpha.Src;
141 			}
142 			presub_src_count
143 				= rc_presubtract_src_reg_count(presub_type);
144 			for(j = 0; j < presub_src_count; j++) {
145 				cb(userdata, fullinst, &sub->Arg[i],
146 								&src_array[j]);
147 			}
148 		} else {
149 			struct rc_pair_instruction_source * src =
150 				rc_pair_get_src(&fullinst->U.P, &sub->Arg[i]);
151 			if (src) {
152 				cb(userdata, fullinst, &sub->Arg[i], src);
153 			}
154 		}
155 	}
156 }
157 
158 /* This function calls the callback function (cb) for each source used by
159  * the instruction.
160  * */
rc_for_all_reads_src(struct rc_instruction * inst,rc_read_src_fn cb,void * userdata)161 void rc_for_all_reads_src(
162 	struct rc_instruction * inst,
163 	rc_read_src_fn cb,
164 	void * userdata)
165 {
166 	const struct rc_opcode_info * opcode =
167 					rc_get_opcode_info(inst->U.I.Opcode);
168 
169 	/* This function only works with normal instructions. */
170 	if (inst->Type != RC_INSTRUCTION_NORMAL) {
171 		assert(0);
172 		return;
173 	}
174 
175 	for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {
176 
177 		if (inst->U.I.SrcReg[src].File == RC_FILE_PRESUB) {
178 			unsigned int i;
179 			unsigned int srcp_regs = rc_presubtract_src_reg_count(
180 						inst->U.I.PreSub.Opcode);
181 			for( i = 0; i < srcp_regs; i++) {
182 				cb(userdata, inst, &inst->U.I.PreSub.SrcReg[i]);
183 			}
184 		} else {
185 			cb(userdata, inst, &inst->U.I.SrcReg[src]);
186 		}
187 	}
188 }
189 
190 /**
191  * This function calls the callback function (cb) for each arg of the RGB and
192  * alpha components.
193  */
rc_pair_for_all_reads_arg(struct rc_instruction * inst,rc_pair_read_arg_fn cb,void * userdata)194 void rc_pair_for_all_reads_arg(
195 	struct rc_instruction * inst,
196 	rc_pair_read_arg_fn cb,
197 	void * userdata)
198 {
199 	/* This function only works with pair instructions. */
200 	if (inst->Type != RC_INSTRUCTION_PAIR) {
201 		assert(0);
202 		return;
203 	}
204 
205 	pair_sub_for_all_args(inst, &inst->U.P.RGB, cb, userdata);
206 	pair_sub_for_all_args(inst, &inst->U.P.Alpha, cb, userdata);
207 }
208 
209 /**
210  * Calls a callback function for all register reads.
211  *
212  * This is conservative, i.e. if the same register is referenced multiple times,
213  * the callback may also be called multiple times.
214  * Also, the writemask of the instruction is not taken into account.
215  */
rc_for_all_reads_mask(struct rc_instruction * inst,rc_read_write_mask_fn cb,void * userdata)216 void rc_for_all_reads_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata)
217 {
218 	if (inst->Type == RC_INSTRUCTION_NORMAL) {
219 		struct read_write_mask_data cb_data;
220 		cb_data.UserData = userdata;
221 		cb_data.Cb = cb;
222 
223 		rc_for_all_reads_src(inst, reads_normal_callback, &cb_data);
224 	} else {
225 		reads_pair(inst, cb, userdata);
226 	}
227 }
228 
229 
230 
writes_normal(struct rc_instruction * fullinst,rc_read_write_mask_fn cb,void * userdata)231 static void writes_normal(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
232 {
233 	struct rc_sub_instruction * inst = &fullinst->U.I;
234 	const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
235 
236 	if (opcode->HasDstReg && inst->DstReg.WriteMask)
237 		cb(userdata, fullinst, inst->DstReg.File, inst->DstReg.Index, inst->DstReg.WriteMask);
238 
239 	if (inst->WriteALUResult)
240 		cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X);
241 }
242 
writes_pair(struct rc_instruction * fullinst,rc_read_write_mask_fn cb,void * userdata)243 static void writes_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
244 {
245 	struct rc_pair_instruction * inst = &fullinst->U.P;
246 
247 	if (inst->RGB.WriteMask)
248 		cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->RGB.DestIndex, inst->RGB.WriteMask);
249 
250 	if (inst->Alpha.WriteMask)
251 		cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->Alpha.DestIndex, RC_MASK_W);
252 
253 	if (inst->WriteALUResult)
254 		cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X);
255 }
256 
257 /**
258  * Calls a callback function for all register writes in the instruction,
259  * reporting writemasks to the callback function.
260  *
261  * \warning Does not report output registers for paired instructions!
262  */
rc_for_all_writes_mask(struct rc_instruction * inst,rc_read_write_mask_fn cb,void * userdata)263 void rc_for_all_writes_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata)
264 {
265 	if (inst->Type == RC_INSTRUCTION_NORMAL) {
266 		writes_normal(inst, cb, userdata);
267 	} else {
268 		writes_pair(inst, cb, userdata);
269 	}
270 }
271 
272 
273 struct mask_to_chan_data {
274 	void * UserData;
275 	rc_read_write_chan_fn Fn;
276 };
277 
mask_to_chan_cb(void * data,struct rc_instruction * inst,rc_register_file file,unsigned int index,unsigned int mask)278 static void mask_to_chan_cb(void * data, struct rc_instruction * inst,
279 		rc_register_file file, unsigned int index, unsigned int mask)
280 {
281 	struct mask_to_chan_data * d = data;
282 	for(unsigned int chan = 0; chan < 4; ++chan) {
283 		if (GET_BIT(mask, chan))
284 			d->Fn(d->UserData, inst, file, index, chan);
285 	}
286 }
287 
288 /**
289  * Calls a callback function for all sourced register channels.
290  *
291  * This is conservative, i.e. channels may be called multiple times,
292  * and the writemask of the instruction is not taken into account.
293  */
rc_for_all_reads_chan(struct rc_instruction * inst,rc_read_write_chan_fn cb,void * userdata)294 void rc_for_all_reads_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata)
295 {
296 	struct mask_to_chan_data d;
297 	d.UserData = userdata;
298 	d.Fn = cb;
299 	rc_for_all_reads_mask(inst, &mask_to_chan_cb, &d);
300 }
301 
302 /**
303  * Calls a callback function for all written register channels.
304  *
305  * \warning Does not report output registers for paired instructions!
306  */
rc_for_all_writes_chan(struct rc_instruction * inst,rc_read_write_chan_fn cb,void * userdata)307 void rc_for_all_writes_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata)
308 {
309 	struct mask_to_chan_data d;
310 	d.UserData = userdata;
311 	d.Fn = cb;
312 	rc_for_all_writes_mask(inst, &mask_to_chan_cb, &d);
313 }
314 
remap_normal_instruction(struct rc_instruction * fullinst,rc_remap_register_fn cb,void * userdata)315 static void remap_normal_instruction(struct rc_instruction * fullinst,
316 		rc_remap_register_fn cb, void * userdata)
317 {
318 	struct rc_sub_instruction * inst = &fullinst->U.I;
319 	const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
320 	unsigned int remapped_presub = 0;
321 
322 	if (opcode->HasDstReg) {
323 		rc_register_file file = inst->DstReg.File;
324 		unsigned int index = inst->DstReg.Index;
325 
326 		cb(userdata, fullinst, &file, &index);
327 
328 		inst->DstReg.File = file;
329 		inst->DstReg.Index = index;
330 	}
331 
332 	for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {
333 		rc_register_file file = inst->SrcReg[src].File;
334 		unsigned int index = inst->SrcReg[src].Index;
335 
336 		if (file == RC_FILE_PRESUB) {
337 			unsigned int i;
338 			unsigned int srcp_srcs = rc_presubtract_src_reg_count(
339 						inst->PreSub.Opcode);
340 			/* Make sure we only remap presubtract sources once in
341 			 * case more than one source register reads the
342 			 * presubtract result. */
343 			if (remapped_presub)
344 				continue;
345 
346 			for(i = 0; i < srcp_srcs; i++) {
347 				file = inst->PreSub.SrcReg[i].File;
348 				index = inst->PreSub.SrcReg[i].Index;
349 				cb(userdata, fullinst, &file, &index);
350 				inst->PreSub.SrcReg[i].File = file;
351 				inst->PreSub.SrcReg[i].Index = index;
352 			}
353 			remapped_presub = 1;
354 		}
355 		else {
356 			cb(userdata, fullinst, &file, &index);
357 
358 			inst->SrcReg[src].File = file;
359 			inst->SrcReg[src].Index = index;
360 		}
361 	}
362 }
363 
remap_pair_instruction(struct rc_instruction * fullinst,rc_remap_register_fn cb,void * userdata)364 static void remap_pair_instruction(struct rc_instruction * fullinst,
365 		rc_remap_register_fn cb, void * userdata)
366 {
367 	struct rc_pair_instruction * inst = &fullinst->U.P;
368 
369 	if (inst->RGB.WriteMask) {
370 		rc_register_file file = RC_FILE_TEMPORARY;
371 		unsigned int index = inst->RGB.DestIndex;
372 
373 		cb(userdata, fullinst, &file, &index);
374 
375 		inst->RGB.DestIndex = index;
376 	}
377 
378 	if (inst->Alpha.WriteMask) {
379 		rc_register_file file = RC_FILE_TEMPORARY;
380 		unsigned int index = inst->Alpha.DestIndex;
381 
382 		cb(userdata, fullinst, &file, &index);
383 
384 		inst->Alpha.DestIndex = index;
385 	}
386 
387 	for(unsigned int src = 0; src < 3; ++src) {
388 		if (inst->RGB.Src[src].Used) {
389 			rc_register_file file = inst->RGB.Src[src].File;
390 			unsigned int index = inst->RGB.Src[src].Index;
391 
392 			cb(userdata, fullinst, &file, &index);
393 
394 			inst->RGB.Src[src].File = file;
395 			inst->RGB.Src[src].Index = index;
396 		}
397 
398 		if (inst->Alpha.Src[src].Used) {
399 			rc_register_file file = inst->Alpha.Src[src].File;
400 			unsigned int index = inst->Alpha.Src[src].Index;
401 
402 			cb(userdata, fullinst, &file, &index);
403 
404 			inst->Alpha.Src[src].File = file;
405 			inst->Alpha.Src[src].Index = index;
406 		}
407 	}
408 }
409 
410 
411 /**
412  * Remap all register accesses according to the given function.
413  * That is, call the function \p cb for each referenced register (both read and written)
414  * and update the given instruction \p inst accordingly
415  * if it modifies its \ref pfile and \ref pindex contents.
416  */
rc_remap_registers(struct rc_instruction * inst,rc_remap_register_fn cb,void * userdata)417 void rc_remap_registers(struct rc_instruction * inst, rc_remap_register_fn cb, void * userdata)
418 {
419 	if (inst->Type == RC_INSTRUCTION_NORMAL)
420 		remap_normal_instruction(inst, cb, userdata);
421 	else
422 		remap_pair_instruction(inst, cb, userdata);
423 }
424 
425 struct branch_write_mask {
426 	unsigned int IfWriteMask:4;
427 	unsigned int ElseWriteMask:4;
428 	unsigned int HasElse:1;
429 };
430 
431 union get_readers_read_cb {
432 	rc_read_src_fn I;
433 	rc_pair_read_arg_fn P;
434 };
435 
436 struct get_readers_callback_data {
437 	struct radeon_compiler * C;
438 	struct rc_reader_data * ReaderData;
439 	rc_read_src_fn ReadNormalCB;
440 	rc_pair_read_arg_fn ReadPairCB;
441 	rc_read_write_mask_fn WriteCB;
442 	rc_register_file DstFile;
443 	unsigned int DstIndex;
444 	unsigned int DstMask;
445 	unsigned int AliveWriteMask;
446 	/*  For convenience, this is indexed starting at 1 */
447 	struct branch_write_mask BranchMasks[R500_PFS_MAX_BRANCH_DEPTH_FULL + 1];
448 };
449 
add_reader(struct memory_pool * pool,struct rc_reader_data * data,struct rc_instruction * inst,unsigned int mask)450 static struct rc_reader * add_reader(
451 	struct memory_pool * pool,
452 	struct rc_reader_data * data,
453 	struct rc_instruction * inst,
454 	unsigned int mask)
455 {
456 	struct rc_reader * new;
457 	memory_pool_array_reserve(pool, struct rc_reader, data->Readers,
458 				data->ReaderCount, data->ReadersReserved, 1);
459 	new = &data->Readers[data->ReaderCount++];
460 	new->Inst = inst;
461 	new->WriteMask = mask;
462 	return new;
463 }
464 
add_reader_normal(struct memory_pool * pool,struct rc_reader_data * data,struct rc_instruction * inst,unsigned int mask,struct rc_src_register * src)465 static void add_reader_normal(
466 	struct memory_pool * pool,
467 	struct rc_reader_data * data,
468 	struct rc_instruction * inst,
469 	unsigned int mask,
470 	struct rc_src_register * src)
471 {
472 	struct rc_reader * new = add_reader(pool, data, inst, mask);
473 	new->U.I.Src = src;
474 }
475 
476 
add_reader_pair(struct memory_pool * pool,struct rc_reader_data * data,struct rc_instruction * inst,unsigned int mask,struct rc_pair_instruction_arg * arg,struct rc_pair_instruction_source * src)477 static void add_reader_pair(
478 	struct memory_pool * pool,
479 	struct rc_reader_data * data,
480 	struct rc_instruction * inst,
481 	unsigned int mask,
482 	struct rc_pair_instruction_arg * arg,
483 	struct rc_pair_instruction_source * src)
484 {
485 	struct rc_reader * new = add_reader(pool, data, inst, mask);
486 	new->U.P.Src = src;
487 	new->U.P.Arg = arg;
488 }
489 
get_readers_read_callback(struct get_readers_callback_data * cb_data,rc_register_file file,unsigned int index,unsigned int swizzle)490 static unsigned int get_readers_read_callback(
491 	struct get_readers_callback_data * cb_data,
492 	rc_register_file file,
493 	unsigned int index,
494 	unsigned int swizzle)
495 {
496 	unsigned int shared_mask, read_mask;
497 
498 	shared_mask = rc_src_reads_dst_mask(file, index, swizzle,
499 		cb_data->DstFile, cb_data->DstIndex, cb_data->AliveWriteMask);
500 
501 	if (shared_mask == RC_MASK_NONE)
502 		return shared_mask;
503 
504 	/* If we make it this far, it means that this source reads from the
505 	 * same register written to by d->ReaderData->Writer. */
506 
507 	read_mask = rc_swizzle_to_writemask(swizzle);
508 	if (cb_data->ReaderData->AbortOnRead & read_mask) {
509 		cb_data->ReaderData->Abort = 1;
510 		return shared_mask;
511 	}
512 
513 	if (cb_data->ReaderData->LoopDepth > 0) {
514 		cb_data->ReaderData->AbortOnWrite |=
515 				(read_mask & cb_data->AliveWriteMask);
516 	}
517 
518 	/* XXX The behavior in this case should be configurable. */
519 	if ((read_mask & cb_data->AliveWriteMask) != read_mask) {
520 		cb_data->ReaderData->Abort = 1;
521 		return shared_mask;
522 	}
523 
524 	return shared_mask;
525 }
526 
get_readers_pair_read_callback(void * userdata,struct rc_instruction * inst,struct rc_pair_instruction_arg * arg,struct rc_pair_instruction_source * src)527 static void get_readers_pair_read_callback(
528 	void * userdata,
529 	struct rc_instruction * inst,
530 	struct rc_pair_instruction_arg * arg,
531 	struct rc_pair_instruction_source * src)
532 {
533 	unsigned int shared_mask;
534 	struct get_readers_callback_data * d = userdata;
535 
536 	shared_mask = get_readers_read_callback(d,
537 				src->File, src->Index, arg->Swizzle);
538 
539 	if (shared_mask == RC_MASK_NONE)
540 		return;
541 
542 	if (d->ReadPairCB)
543 		d->ReadPairCB(d->ReaderData, inst, arg, src);
544 
545 	if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort)
546 		return;
547 
548 	add_reader_pair(&d->C->Pool, d->ReaderData, inst, shared_mask, arg, src);
549 }
550 
551 /**
552  * This function is used by rc_get_readers_normal() to determine whether inst
553  * is a reader of userdata->ReaderData->Writer
554  */
get_readers_normal_read_callback(void * userdata,struct rc_instruction * inst,struct rc_src_register * src)555 static void get_readers_normal_read_callback(
556 	void * userdata,
557 	struct rc_instruction * inst,
558 	struct rc_src_register * src)
559 {
560 	struct get_readers_callback_data * d = userdata;
561 	unsigned int shared_mask;
562 
563 	shared_mask = get_readers_read_callback(d,
564 			src->File, src->Index, src->Swizzle);
565 
566 	if (shared_mask == RC_MASK_NONE)
567 		return;
568 	/* The callback function could potentially clear d->ReaderData->Abort,
569 	 * so we need to call it before we return. */
570 	if (d->ReadNormalCB)
571 		d->ReadNormalCB(d->ReaderData, inst, src);
572 
573 	if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort)
574 		return;
575 
576 	add_reader_normal(&d->C->Pool, d->ReaderData, inst, shared_mask, src);
577 }
578 
579 /**
580  * This function is used by rc_get_readers_normal() to determine when
581  * userdata->ReaderData->Writer is dead (i. e. All components of its
582  * destination register have been overwritten by other instructions).
583  */
get_readers_write_callback(void * userdata,struct rc_instruction * inst,rc_register_file file,unsigned int index,unsigned int mask)584 static void get_readers_write_callback(
585 	void *userdata,
586 	struct rc_instruction * inst,
587 	rc_register_file file,
588 	unsigned int index,
589 	unsigned int mask)
590 {
591 	struct get_readers_callback_data * d = userdata;
592 
593 	if (index == d->DstIndex && file == d->DstFile) {
594 		unsigned int shared_mask = mask & d->DstMask;
595 		d->ReaderData->AbortOnRead &= ~shared_mask;
596 		d->AliveWriteMask &= ~shared_mask;
597 		if (d->ReaderData->AbortOnWrite & shared_mask) {
598 			d->ReaderData->Abort = 1;
599 		}
600 	}
601 
602 	if(d->WriteCB)
603 		d->WriteCB(d->ReaderData, inst, file, index, mask);
604 }
605 
push_branch_mask(struct get_readers_callback_data * d,unsigned int * branch_depth)606 static void push_branch_mask(
607 	struct get_readers_callback_data * d,
608 	unsigned int * branch_depth)
609 {
610 	(*branch_depth)++;
611 	if (*branch_depth > R500_PFS_MAX_BRANCH_DEPTH_FULL) {
612 		d->ReaderData->Abort = 1;
613 		return;
614 	}
615 	d->BranchMasks[*branch_depth].IfWriteMask =
616 					d->AliveWriteMask;
617 }
618 
pop_branch_mask(struct get_readers_callback_data * d,unsigned int * branch_depth)619 static void pop_branch_mask(
620 	struct get_readers_callback_data * d,
621 	unsigned int * branch_depth)
622 {
623 	struct branch_write_mask * masks = &d->BranchMasks[*branch_depth];
624 
625 	if (masks->HasElse) {
626 		/* Abort on read for components that were written in the IF
627 		 * block. */
628 		d->ReaderData->AbortOnRead |=
629 				masks->IfWriteMask & ~masks->ElseWriteMask;
630 		/* Abort on read for components that were written in the ELSE
631 		 * block. */
632 		d->ReaderData->AbortOnRead |=
633 				masks->ElseWriteMask & ~d->AliveWriteMask;
634 
635 		d->AliveWriteMask = masks->IfWriteMask
636 			^ ((masks->IfWriteMask ^ masks->ElseWriteMask)
637 			& (masks->IfWriteMask ^ d->AliveWriteMask));
638 	} else {
639 		d->ReaderData->AbortOnRead |=
640 				masks->IfWriteMask & ~d->AliveWriteMask;
641 		d->AliveWriteMask = masks->IfWriteMask;
642 
643 	}
644 	memset(masks, 0, sizeof(struct branch_write_mask));
645 	(*branch_depth)--;
646 }
647 
get_readers_for_single_write(void * userdata,struct rc_instruction * writer,rc_register_file dst_file,unsigned int dst_index,unsigned int dst_mask)648 static void get_readers_for_single_write(
649 	void * userdata,
650 	struct rc_instruction * writer,
651 	rc_register_file dst_file,
652 	unsigned int dst_index,
653 	unsigned int dst_mask)
654 {
655 	struct rc_instruction * tmp;
656 	unsigned int branch_depth = 0;
657 	struct rc_instruction * endloop = NULL;
658 	unsigned int abort_on_read_at_endloop = 0;
659 	unsigned int abort_on_read_at_break = 0;
660 	unsigned int alive_write_mask_at_breaks = 0;
661 	struct get_readers_callback_data * d = userdata;
662 
663 	d->ReaderData->Writer = writer;
664 	d->ReaderData->AbortOnRead = 0;
665 	d->ReaderData->AbortOnWrite = 0;
666 	d->ReaderData->LoopDepth = 0;
667 	d->ReaderData->InElse = 0;
668 	d->DstFile = dst_file;
669 	d->DstIndex = dst_index;
670 	d->DstMask = dst_mask;
671 	d->AliveWriteMask = dst_mask;
672 	memset(d->BranchMasks, 0, sizeof(d->BranchMasks));
673 
674 	if (!dst_mask)
675 		return;
676 
677 	for(tmp = writer->Next; tmp != &d->C->Program.Instructions;
678 							tmp = tmp->Next){
679 		rc_opcode opcode = rc_get_flow_control_inst(tmp);
680 		switch(opcode) {
681 		case RC_OPCODE_BGNLOOP:
682 			d->ReaderData->LoopDepth++;
683 			push_branch_mask(d, &branch_depth);
684 			break;
685 		case RC_OPCODE_ENDLOOP:
686 			if (d->ReaderData->LoopDepth > 0) {
687 				d->ReaderData->LoopDepth--;
688 				if (d->ReaderData->LoopDepth == 0) {
689 					d->ReaderData->AbortOnWrite = 0;
690 				}
691 				pop_branch_mask(d, &branch_depth);
692 			} else {
693 				/* Here we have reached an ENDLOOP without
694 				 * seeing its BGNLOOP.  These means that
695 				 * the writer was written inside of a loop,
696 				 * so it could have readers that are above it
697 				 * (i.e. they have a lower IP).  To find these
698 				 * readers we jump to the BGNLOOP instruction
699 				 * and check each instruction until we get
700 				 * back to the writer.
701 				 */
702 				endloop = tmp;
703 				tmp = rc_match_endloop(tmp);
704 				if (!tmp) {
705 					rc_error(d->C, "Failed to match endloop.\n");
706 					d->ReaderData->Abort = 1;
707 					return;
708 				}
709 				abort_on_read_at_endloop = d->ReaderData->AbortOnRead;
710 				d->ReaderData->AbortOnRead |= d->AliveWriteMask;
711 				continue;
712 			}
713 			break;
714 		case RC_OPCODE_BRK:
715 			if (branch_depth == 0 && d->ReaderData->LoopDepth == 0) {
716 				tmp = rc_match_bgnloop(tmp);
717 				d->ReaderData->AbortOnRead = d->AliveWriteMask;
718 			} else {
719 				struct branch_write_mask * masks = &d->BranchMasks[branch_depth];
720 				alive_write_mask_at_breaks |= d->AliveWriteMask;
721 				if (masks->HasElse) {
722 					/* Abort on read for components that were written in the IF
723 					 * block. */
724 					abort_on_read_at_break |=
725 						masks->IfWriteMask & ~masks->ElseWriteMask;
726 					/* Abort on read for components that were written in the ELSE
727 					 * block. */
728 					abort_on_read_at_break |=
729 						masks->ElseWriteMask & ~d->AliveWriteMask;
730 				} else {
731 					abort_on_read_at_break |=
732 						masks->IfWriteMask & ~d->AliveWriteMask;
733 				}
734 			}
735 			break;
736 		case RC_OPCODE_IF:
737 			push_branch_mask(d, &branch_depth);
738 			break;
739 		case RC_OPCODE_ELSE:
740 			if (branch_depth == 0) {
741 				d->ReaderData->InElse = 1;
742 			} else {
743 				unsigned int temp_mask = d->AliveWriteMask;
744 				d->AliveWriteMask =
745 					d->BranchMasks[branch_depth].IfWriteMask;
746 				d->BranchMasks[branch_depth].ElseWriteMask =
747 								temp_mask;
748 				d->BranchMasks[branch_depth].HasElse = 1;
749 			}
750 			break;
751 		case RC_OPCODE_ENDIF:
752 			if (branch_depth == 0) {
753 				d->ReaderData->AbortOnRead = d->AliveWriteMask;
754 				d->ReaderData->InElse = 0;
755 			}
756 			else {
757 				pop_branch_mask(d, &branch_depth);
758 			}
759 			break;
760 		default:
761 			break;
762 		}
763 
764 		if (d->ReaderData->InElse)
765 			continue;
766 
767 		if (tmp->Type == RC_INSTRUCTION_NORMAL) {
768 			rc_for_all_reads_src(tmp,
769 				get_readers_normal_read_callback, d);
770 		} else {
771 			rc_pair_for_all_reads_arg(tmp,
772 				get_readers_pair_read_callback, d);
773 		}
774 
775 		/* This can happen when we jump from an ENDLOOP to BGNLOOP */
776 		if (tmp == writer) {
777 			tmp = endloop;
778 			endloop = NULL;
779 			d->ReaderData->AbortOnRead = abort_on_read_at_endloop
780 							| abort_on_read_at_break;
781 			/* Restore the AliveWriteMask to account for all possible
782 			 * exits from the loop. */
783 			d->AliveWriteMask = alive_write_mask_at_breaks;
784 			alive_write_mask_at_breaks = 0;
785 			continue;
786 		}
787 		rc_for_all_writes_mask(tmp, get_readers_write_callback, d);
788 
789 		if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort)
790 			return;
791 
792 		/* The check for !endloop in needed for the following scenario:
793 		 *
794 		 * 0 MOV TEMP[0] none.0
795 		 * 1 BGNLOOP
796 		 * 2   IF some exit condition
797 		 * 3      BRK
798 		 * 4   ENDIF
799 		 * 5 ADD TEMP[0], TEMP[0], CONST[0]
800 		 * 6 ADD TEMP[0], TEMP[0], none.1
801 		 * 7 ENDLOOP
802 		 * 8 MOV OUT[0] TEMP[0]
803 		 *
804 		 * When we search for the readers of instruction 6, we encounter the ENDLOOP
805 		 * and continue searching at BGNLOOP. At instruction 5 the AliveWriteMask
806 		 * becomes 0 and we would stop the search. However we still need to continue
807 		 * back to 6 from which we jump after the endloop, restore the AliveWriteMask
808 		 * according to the possible states at breaks and continue after the loop.
809                  */
810 		if (branch_depth == 0 && !d->AliveWriteMask && !endloop)
811 			return;
812 	}
813 }
814 
init_get_readers_callback_data(struct get_readers_callback_data * d,struct rc_reader_data * reader_data,struct radeon_compiler * c,rc_read_src_fn read_normal_cb,rc_pair_read_arg_fn read_pair_cb,rc_read_write_mask_fn write_cb)815 static void init_get_readers_callback_data(
816 	struct get_readers_callback_data * d,
817 	struct rc_reader_data * reader_data,
818 	struct radeon_compiler * c,
819 	rc_read_src_fn read_normal_cb,
820 	rc_pair_read_arg_fn read_pair_cb,
821 	rc_read_write_mask_fn write_cb)
822 {
823 	reader_data->C = c;
824 	reader_data->Abort = 0;
825 	reader_data->ReaderCount = 0;
826 	reader_data->ReadersReserved = 0;
827 	reader_data->Readers = NULL;
828 
829 	d->C = c;
830 	d->ReaderData = reader_data;
831 	d->ReadNormalCB = read_normal_cb;
832 	d->ReadPairCB = read_pair_cb;
833 	d->WriteCB = write_cb;
834 }
835 
836 /**
837  * This function will create a list of readers via the rc_reader_data struct.
838  * This function will abort (set the flag data->Abort) and return if it
839  * encounters an instruction that reads from @param writer and also a different
840  * instruction.  Here are some examples:
841  *
842  * writer = instruction 0;
843  * 0 MOV TEMP[0].xy, TEMP[1].xy
844  * 1 MOV TEMP[0].zw, TEMP[2].xy
845  * 2 MOV TEMP[3], TEMP[0]
846  * The Abort flag will be set on instruction 2, because it reads values written
847  * by instructions 0 and 1.
848  *
849  * writer = instruction 1;
850  * 0 IF TEMP[0].x
851  * 1 MOV TEMP[1], TEMP[2]
852  * 2 ELSE
853  * 3 MOV TEMP[1], TEMP[2]
854  * 4 ENDIF
855  * 5 MOV TEMP[3], TEMP[1]
856  * The Abort flag will be set on instruction 5, because it could read from the
857  * value written by either instruction 1 or 3, depending on the jump decision
858  * made at instruction 0.
859  *
860  * writer = instruction 0;
861  * 0 MOV TEMP[0], TEMP[1]
862  * 2 BGNLOOP
863  * 3 ADD TEMP[0], TEMP[0], none.1
864  * 4 ENDLOOP
865  * The Abort flag will be set on instruction 3, because in the first iteration
866  * of the loop it reads the value written by instruction 0 and in all other
867  * iterations it reads the value written by instruction 3.
868  *
869  * @param read_cb This function will be called for every instruction that
870  * has been determined to be a reader of writer.
871  * @param write_cb This function will be called for every instruction after
872  * writer.
873  */
rc_get_readers(struct radeon_compiler * c,struct rc_instruction * writer,struct rc_reader_data * data,rc_read_src_fn read_normal_cb,rc_pair_read_arg_fn read_pair_cb,rc_read_write_mask_fn write_cb)874 void rc_get_readers(
875 	struct radeon_compiler * c,
876 	struct rc_instruction * writer,
877 	struct rc_reader_data * data,
878 	rc_read_src_fn read_normal_cb,
879 	rc_pair_read_arg_fn read_pair_cb,
880 	rc_read_write_mask_fn write_cb)
881 {
882 	struct get_readers_callback_data d;
883 
884 	init_get_readers_callback_data(&d, data, c, read_normal_cb,
885 						read_pair_cb, write_cb);
886 
887 	rc_for_all_writes_mask(writer, get_readers_for_single_write, &d);
888 }
889 
rc_get_readers_sub(struct radeon_compiler * c,struct rc_instruction * writer,struct rc_pair_sub_instruction * sub_writer,struct rc_reader_data * data,rc_read_src_fn read_normal_cb,rc_pair_read_arg_fn read_pair_cb,rc_read_write_mask_fn write_cb)890 void rc_get_readers_sub(
891 	struct radeon_compiler * c,
892 	struct rc_instruction * writer,
893 	struct rc_pair_sub_instruction * sub_writer,
894 	struct rc_reader_data * data,
895 	rc_read_src_fn read_normal_cb,
896 	rc_pair_read_arg_fn read_pair_cb,
897 	rc_read_write_mask_fn write_cb)
898 {
899 	struct get_readers_callback_data d;
900 
901 	init_get_readers_callback_data(&d, data, c, read_normal_cb,
902 						read_pair_cb, write_cb);
903 
904 	if (sub_writer->WriteMask) {
905 		get_readers_for_single_write(&d, writer, RC_FILE_TEMPORARY,
906 			sub_writer->DestIndex, sub_writer->WriteMask);
907 	}
908 }
909