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