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