r300/compiler: Standardize the number of bits used by swizzle fields
[mesa.git] / src / mesa / drivers / dri / r300 / compiler / radeon_dataflow.c
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
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
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
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
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 if (src_type & RC_SOURCE_RGB) {
155 presub_type = fullinst->
156 U.P.RGB.Src[RC_PAIR_PRESUB_SRC].Index;
157 src_array = fullinst->U.P.RGB.Src;
158 } else {
159 presub_type = fullinst->
160 U.P.Alpha.Src[RC_PAIR_PRESUB_SRC].Index;
161 src_array = fullinst->U.P.Alpha.Src;
162 }
163 presub_src_count
164 = rc_presubtract_src_reg_count(presub_type);
165 for(j = 0; j < presub_src_count; j++) {
166 cb(userdata, fullinst, &sub->Arg[i],
167 &src_array[j]);
168 }
169 } else {
170 struct rc_pair_instruction_source * src =
171 rc_pair_get_src(&fullinst->U.P, &sub->Arg[i]);
172 if (src) {
173 cb(userdata, fullinst, &sub->Arg[i], src);
174 }
175 }
176 }
177 }
178
179 /* This function calls the callback function (cb) for each source used by
180 * the instruction.
181 * */
182 void rc_for_all_reads_src(
183 struct rc_instruction * inst,
184 rc_read_src_fn cb,
185 void * userdata)
186 {
187 const struct rc_opcode_info * opcode =
188 rc_get_opcode_info(inst->U.I.Opcode);
189
190 /* This function only works with normal instructions. */
191 if (inst->Type != RC_INSTRUCTION_NORMAL) {
192 assert(0);
193 return;
194 }
195
196 for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {
197
198 if (inst->U.I.SrcReg[src].File == RC_FILE_NONE)
199 continue;
200
201 if (inst->U.I.SrcReg[src].File == RC_FILE_PRESUB) {
202 unsigned int i;
203 unsigned int srcp_regs = rc_presubtract_src_reg_count(
204 inst->U.I.PreSub.Opcode);
205 for( i = 0; i < srcp_regs; i++) {
206 cb(userdata, inst, &inst->U.I.PreSub.SrcReg[i]);
207 }
208 } else {
209 cb(userdata, inst, &inst->U.I.SrcReg[src]);
210 }
211 }
212 }
213
214 /**
215 * This function calls the callback function (cb) for each arg of the RGB and
216 * alpha components.
217 */
218 void rc_pair_for_all_reads_arg(
219 struct rc_instruction * inst,
220 rc_pair_read_arg_fn cb,
221 void * userdata)
222 {
223 /* This function only works with pair instructions. */
224 if (inst->Type != RC_INSTRUCTION_PAIR) {
225 assert(0);
226 return;
227 }
228
229 pair_sub_for_all_args(inst, &inst->U.P.RGB, cb, userdata);
230 pair_sub_for_all_args(inst, &inst->U.P.Alpha, cb, userdata);
231 }
232
233 /**
234 * Calls a callback function for all register reads.
235 *
236 * This is conservative, i.e. if the same register is referenced multiple times,
237 * the callback may also be called multiple times.
238 * Also, the writemask of the instruction is not taken into account.
239 */
240 void rc_for_all_reads_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata)
241 {
242 if (inst->Type == RC_INSTRUCTION_NORMAL) {
243 struct read_write_mask_data cb_data;
244 cb_data.UserData = userdata;
245 cb_data.Cb = cb;
246
247 rc_for_all_reads_src(inst, reads_normal_callback, &cb_data);
248 } else {
249 reads_pair(inst, cb, userdata);
250 }
251 }
252
253
254
255 static void writes_normal(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
256 {
257 struct rc_sub_instruction * inst = &fullinst->U.I;
258 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
259
260 if (opcode->HasDstReg && inst->DstReg.WriteMask)
261 cb(userdata, fullinst, inst->DstReg.File, inst->DstReg.Index, inst->DstReg.WriteMask);
262
263 if (inst->WriteALUResult)
264 cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X);
265 }
266
267 static void writes_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
268 {
269 struct rc_pair_instruction * inst = &fullinst->U.P;
270
271 if (inst->RGB.WriteMask)
272 cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->RGB.DestIndex, inst->RGB.WriteMask);
273
274 if (inst->Alpha.WriteMask)
275 cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->Alpha.DestIndex, RC_MASK_W);
276
277 if (inst->WriteALUResult)
278 cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X);
279 }
280
281 /**
282 * Calls a callback function for all register writes in the instruction,
283 * reporting writemasks to the callback function.
284 *
285 * \warning Does not report output registers for paired instructions!
286 */
287 void rc_for_all_writes_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata)
288 {
289 if (inst->Type == RC_INSTRUCTION_NORMAL) {
290 writes_normal(inst, cb, userdata);
291 } else {
292 writes_pair(inst, cb, userdata);
293 }
294 }
295
296
297 struct mask_to_chan_data {
298 void * UserData;
299 rc_read_write_chan_fn Fn;
300 };
301
302 static void mask_to_chan_cb(void * data, struct rc_instruction * inst,
303 rc_register_file file, unsigned int index, unsigned int mask)
304 {
305 struct mask_to_chan_data * d = data;
306 for(unsigned int chan = 0; chan < 4; ++chan) {
307 if (GET_BIT(mask, chan))
308 d->Fn(d->UserData, inst, file, index, chan);
309 }
310 }
311
312 /**
313 * Calls a callback function for all sourced register channels.
314 *
315 * This is conservative, i.e. channels may be called multiple times,
316 * and the writemask of the instruction is not taken into account.
317 */
318 void rc_for_all_reads_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata)
319 {
320 struct mask_to_chan_data d;
321 d.UserData = userdata;
322 d.Fn = cb;
323 rc_for_all_reads_mask(inst, &mask_to_chan_cb, &d);
324 }
325
326 /**
327 * Calls a callback function for all written register channels.
328 *
329 * \warning Does not report output registers for paired instructions!
330 */
331 void rc_for_all_writes_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata)
332 {
333 struct mask_to_chan_data d;
334 d.UserData = userdata;
335 d.Fn = cb;
336 rc_for_all_writes_mask(inst, &mask_to_chan_cb, &d);
337 }
338
339 static void remap_normal_instruction(struct rc_instruction * fullinst,
340 rc_remap_register_fn cb, void * userdata)
341 {
342 struct rc_sub_instruction * inst = &fullinst->U.I;
343 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
344 unsigned int remapped_presub = 0;
345
346 if (opcode->HasDstReg) {
347 rc_register_file file = inst->DstReg.File;
348 unsigned int index = inst->DstReg.Index;
349
350 cb(userdata, fullinst, &file, &index);
351
352 inst->DstReg.File = file;
353 inst->DstReg.Index = index;
354 }
355
356 for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {
357 rc_register_file file = inst->SrcReg[src].File;
358 unsigned int index = inst->SrcReg[src].Index;
359
360 if (file == RC_FILE_PRESUB) {
361 unsigned int i;
362 unsigned int srcp_srcs = rc_presubtract_src_reg_count(
363 inst->PreSub.Opcode);
364 /* Make sure we only remap presubtract sources once in
365 * case more than one source register reads the
366 * presubtract result. */
367 if (remapped_presub)
368 continue;
369
370 for(i = 0; i < srcp_srcs; i++) {
371 file = inst->PreSub.SrcReg[i].File;
372 index = inst->PreSub.SrcReg[i].Index;
373 cb(userdata, fullinst, &file, &index);
374 inst->PreSub.SrcReg[i].File = file;
375 inst->PreSub.SrcReg[i].Index = index;
376 }
377 remapped_presub = 1;
378 }
379 else {
380 cb(userdata, fullinst, &file, &index);
381
382 inst->SrcReg[src].File = file;
383 inst->SrcReg[src].Index = index;
384 }
385 }
386 }
387
388 static void remap_pair_instruction(struct rc_instruction * fullinst,
389 rc_remap_register_fn cb, void * userdata)
390 {
391 struct rc_pair_instruction * inst = &fullinst->U.P;
392
393 if (inst->RGB.WriteMask) {
394 rc_register_file file = RC_FILE_TEMPORARY;
395 unsigned int index = inst->RGB.DestIndex;
396
397 cb(userdata, fullinst, &file, &index);
398
399 inst->RGB.DestIndex = index;
400 }
401
402 if (inst->Alpha.WriteMask) {
403 rc_register_file file = RC_FILE_TEMPORARY;
404 unsigned int index = inst->Alpha.DestIndex;
405
406 cb(userdata, fullinst, &file, &index);
407
408 inst->Alpha.DestIndex = index;
409 }
410
411 for(unsigned int src = 0; src < 3; ++src) {
412 if (inst->RGB.Src[src].Used) {
413 rc_register_file file = inst->RGB.Src[src].File;
414 unsigned int index = inst->RGB.Src[src].Index;
415
416 cb(userdata, fullinst, &file, &index);
417
418 inst->RGB.Src[src].File = file;
419 inst->RGB.Src[src].Index = index;
420 }
421
422 if (inst->Alpha.Src[src].Used) {
423 rc_register_file file = inst->Alpha.Src[src].File;
424 unsigned int index = inst->Alpha.Src[src].Index;
425
426 cb(userdata, fullinst, &file, &index);
427
428 inst->Alpha.Src[src].File = file;
429 inst->Alpha.Src[src].Index = index;
430 }
431 }
432 }
433
434
435 /**
436 * Remap all register accesses according to the given function.
437 * That is, call the function \p cb for each referenced register (both read and written)
438 * and update the given instruction \p inst accordingly
439 * if it modifies its \ref pfile and \ref pindex contents.
440 */
441 void rc_remap_registers(struct rc_instruction * inst, rc_remap_register_fn cb, void * userdata)
442 {
443 if (inst->Type == RC_INSTRUCTION_NORMAL)
444 remap_normal_instruction(inst, cb, userdata);
445 else
446 remap_pair_instruction(inst, cb, userdata);
447 }
448
449 /**
450 * @return RC_OPCODE_NOOP if inst is not a flow control instruction.
451 * @return The opcode of inst if it is a flow control instruction.
452 */
453 static rc_opcode get_flow_control_inst(struct rc_instruction * inst)
454 {
455 const struct rc_opcode_info * info;
456 if (inst->Type == RC_INSTRUCTION_NORMAL) {
457 info = rc_get_opcode_info(inst->U.I.Opcode);
458 } else {
459 info = rc_get_opcode_info(inst->U.P.RGB.Opcode);
460 /*A flow control instruction shouldn't have an alpha
461 * instruction.*/
462 assert(!info->IsFlowControl ||
463 inst->U.P.Alpha.Opcode == RC_OPCODE_NOP);
464 }
465
466 if (info->IsFlowControl)
467 return info->Opcode;
468 else
469 return RC_OPCODE_NOP;
470
471 }
472
473 struct branch_write_mask {
474 unsigned int IfWriteMask:4;
475 unsigned int ElseWriteMask:4;
476 unsigned int HasElse:1;
477 };
478
479 union get_readers_read_cb {
480 rc_read_src_fn I;
481 rc_pair_read_arg_fn P;
482 };
483
484 struct get_readers_callback_data {
485 struct radeon_compiler * C;
486 struct rc_reader_data * ReaderData;
487 rc_read_src_fn ReadNormalCB;
488 rc_pair_read_arg_fn ReadPairCB;
489 rc_read_write_mask_fn WriteCB;
490 rc_register_file DstFile;
491 unsigned int DstIndex;
492 unsigned int DstMask;
493 unsigned int AliveWriteMask;
494 /* For convenience, this is indexed starting at 1 */
495 struct branch_write_mask BranchMasks[R500_PFS_MAX_BRANCH_DEPTH_FULL + 1];
496 };
497
498 static void add_reader(
499 struct memory_pool * pool,
500 struct rc_reader_data * data,
501 struct rc_instruction * inst,
502 unsigned int mask,
503 void * arg_or_src)
504 {
505 struct rc_reader * new;
506 memory_pool_array_reserve(pool, struct rc_reader, data->Readers,
507 data->ReaderCount, data->ReadersReserved, 1);
508 new = &data->Readers[data->ReaderCount++];
509 new->Inst = inst;
510 new->WriteMask = mask;
511 if (inst->Type == RC_INSTRUCTION_NORMAL) {
512 new->U.Src = arg_or_src;
513 } else {
514 new->U.Arg = arg_or_src;
515 }
516 }
517
518 static unsigned int get_readers_read_callback(
519 struct get_readers_callback_data * cb_data,
520 unsigned int has_rel_addr,
521 rc_register_file file,
522 unsigned int index,
523 unsigned int swizzle)
524 {
525 unsigned int shared_mask, read_mask;
526
527 if (has_rel_addr) {
528 cb_data->ReaderData->Abort = 1;
529 return RC_MASK_NONE;
530 }
531
532 shared_mask = rc_src_reads_dst_mask(file, index, swizzle,
533 cb_data->DstFile, cb_data->DstIndex, cb_data->AliveWriteMask);
534
535 if (shared_mask == RC_MASK_NONE)
536 return shared_mask;
537
538 /* If we make it this far, it means that this source reads from the
539 * same register written to by d->ReaderData->Writer. */
540
541 read_mask = rc_swizzle_to_writemask(swizzle);
542 if (cb_data->ReaderData->AbortOnRead & read_mask) {
543 cb_data->ReaderData->Abort = 1;
544 return shared_mask;
545 }
546
547 /* XXX The behavior in this case should be configurable. */
548 if ((read_mask & cb_data->AliveWriteMask) != read_mask) {
549 cb_data->ReaderData->Abort = 1;
550 return shared_mask;
551 }
552
553 return shared_mask;
554 }
555
556 static void get_readers_pair_read_callback(
557 void * userdata,
558 struct rc_instruction * inst,
559 struct rc_pair_instruction_arg * arg,
560 struct rc_pair_instruction_source * src)
561 {
562 unsigned int shared_mask;
563 struct get_readers_callback_data * d = userdata;
564
565 shared_mask = get_readers_read_callback(d,
566 0 /*Pair Instructions don't use RelAddr*/,
567 src->File, src->Index, arg->Swizzle);
568
569 if (shared_mask == RC_MASK_NONE)
570 return;
571
572 if (d->ReadPairCB)
573 d->ReadPairCB(d->ReaderData, inst, arg, src);
574
575 if (d->ReaderData->Abort)
576 return;
577
578 add_reader(&d->C->Pool, d->ReaderData, inst, shared_mask, arg);
579 }
580
581 /**
582 * This function is used by rc_get_readers_normal() to determine whether inst
583 * is a reader of userdata->ReaderData->Writer
584 */
585 static void get_readers_normal_read_callback(
586 void * userdata,
587 struct rc_instruction * inst,
588 struct rc_src_register * src)
589 {
590 struct get_readers_callback_data * d = userdata;
591 unsigned int shared_mask;
592
593 shared_mask = get_readers_read_callback(d,
594 src->RelAddr, src->File, src->Index, src->Swizzle);
595
596 if (shared_mask == RC_MASK_NONE)
597 return;
598 /* The callback function could potentially clear d->ReaderData->Abort,
599 * so we need to call it before we return. */
600 if (d->ReadNormalCB)
601 d->ReadNormalCB(d->ReaderData, inst, src);
602
603 if (d->ReaderData->Abort)
604 return;
605
606 add_reader(&d->C->Pool, d->ReaderData, inst, shared_mask, src);
607 }
608
609 /**
610 * This function is used by rc_get_readers_normal() to determine when
611 * userdata->ReaderData->Writer is dead (i. e. All compontents of its
612 * destination register have been overwritten by other instructions).
613 */
614 static void get_readers_write_callback(
615 void *userdata,
616 struct rc_instruction * inst,
617 rc_register_file file,
618 unsigned int index,
619 unsigned int mask)
620 {
621 struct get_readers_callback_data * d = userdata;
622
623 if (index == d->DstIndex && file == d->DstFile) {
624 unsigned int shared_mask = mask & d->DstMask;
625 d->ReaderData->AbortOnRead &= ~shared_mask;
626 d->AliveWriteMask &= ~shared_mask;
627 }
628
629 if(d->WriteCB)
630 d->WriteCB(d->ReaderData, inst, file, index, mask);
631 }
632
633 static void get_readers_for_single_write(
634 void * userdata,
635 struct rc_instruction * writer,
636 rc_register_file dst_file,
637 unsigned int dst_index,
638 unsigned int dst_mask)
639 {
640 struct rc_instruction * tmp;
641 unsigned int branch_depth = 0;
642 struct get_readers_callback_data * d = userdata;
643
644 d->ReaderData->Writer = writer;
645 d->ReaderData->AbortOnRead = 0;
646 d->ReaderData->InElse = 0;
647 d->DstFile = dst_file;
648 d->DstIndex = dst_index;
649 d->DstMask = dst_mask;
650 d->AliveWriteMask = dst_mask;
651 memset(d->BranchMasks, 0, sizeof(d->BranchMasks));
652
653 if (!dst_mask)
654 return;
655
656 for(tmp = writer->Next; tmp != &d->C->Program.Instructions;
657 tmp = tmp->Next){
658 rc_opcode opcode = get_flow_control_inst(tmp);
659 switch(opcode) {
660 case RC_OPCODE_BGNLOOP:
661 /* XXX We can do better when we see a BGNLOOP if we
662 * add a flag called AbortOnWrite to struct
663 * rc_reader_data and leave it set until the next
664 * ENDLOOP. */
665 case RC_OPCODE_ENDLOOP:
666 /* XXX We can do better when we see an ENDLOOP by
667 * searching backwards from writer and looking for
668 * readers of writer's destination index. If we find a
669 * reader before we get to the BGNLOOP, we must abort
670 * unless there is another writer between that reader
671 * and the BGNLOOP. */
672 case RC_OPCODE_BRK:
673 case RC_OPCODE_CONT:
674 d->ReaderData->Abort = 1;
675 return;
676 case RC_OPCODE_IF:
677 branch_depth++;
678 if (branch_depth > R500_PFS_MAX_BRANCH_DEPTH_FULL) {
679 d->ReaderData->Abort = 1;
680 return;
681 }
682 d->BranchMasks[branch_depth].IfWriteMask =
683 d->AliveWriteMask;
684 break;
685 case RC_OPCODE_ELSE:
686 if (branch_depth == 0) {
687 d->ReaderData->InElse = 1;
688 } else {
689 unsigned int temp_mask = d->AliveWriteMask;
690 d->AliveWriteMask =
691 d->BranchMasks[branch_depth].IfWriteMask;
692 d->BranchMasks[branch_depth].ElseWriteMask =
693 temp_mask;
694 d->BranchMasks[branch_depth].HasElse = 1;
695 }
696 break;
697 case RC_OPCODE_ENDIF:
698 if (branch_depth == 0) {
699 d->ReaderData->AbortOnRead = d->AliveWriteMask;
700 d->ReaderData->InElse = 0;
701 }
702 else {
703 struct branch_write_mask * masks =
704 &d->BranchMasks[branch_depth];
705
706 if (masks->HasElse) {
707 d->ReaderData->AbortOnRead |=
708 masks->IfWriteMask
709 & ~masks->ElseWriteMask;
710 d->AliveWriteMask = masks->IfWriteMask
711 ^ ((masks->IfWriteMask ^
712 masks->ElseWriteMask)
713 & (masks->IfWriteMask
714 ^ d->AliveWriteMask));
715 } else {
716 d->ReaderData->AbortOnRead |=
717 masks->IfWriteMask
718 & ~d->AliveWriteMask;
719 d->AliveWriteMask = masks->IfWriteMask;
720
721 }
722 memset(masks, 0,
723 sizeof(struct branch_write_mask));
724 branch_depth--;
725 }
726 break;
727 default:
728 break;
729 }
730
731 if (d->ReaderData->InElse)
732 continue;
733
734 if (tmp->Type == RC_INSTRUCTION_NORMAL) {
735 rc_for_all_reads_src(tmp,
736 get_readers_normal_read_callback, d);
737 } else {
738 rc_pair_for_all_reads_arg(tmp,
739 get_readers_pair_read_callback, d);
740 }
741 rc_for_all_writes_mask(tmp, get_readers_write_callback, d);
742
743 if (d->ReaderData->Abort)
744 return;
745
746 if (branch_depth == 0 && !d->AliveWriteMask)
747 return;
748 }
749 }
750
751 /**
752 * This function will create a list of readers via the rc_reader_data struct.
753 * This function will abort (set the flag data->Abort) and return if it
754 * encounters an instruction that reads from @param writer and also a different
755 * instruction. Here are some examples:
756 *
757 * writer = instruction 0;
758 * 0 MOV TEMP[0].xy, TEMP[1].xy
759 * 1 MOV TEMP[0].zw, TEMP[2].xy
760 * 2 MOV TEMP[3], TEMP[0]
761 * The Abort flag will be set on instruction 2, because it reads values written
762 * by instructions 0 and 1.
763 *
764 * writer = instruction 1;
765 * 0 IF TEMP[0].x
766 * 1 MOV TEMP[1], TEMP[2]
767 * 2 ELSE
768 * 3 MOV TEMP[1], TEMP[2]
769 * 4 ENDIF
770 * 5 MOV TEMP[3], TEMP[1]
771 * The Abort flag will be set on instruction 5, because it could read from the
772 * value written by either instruction 1 or 3, depending on the jump decision
773 * made at instruction 0.
774 *
775 * writer = instruction 0;
776 * 0 MOV TEMP[0], TEMP[1]
777 * 2 BGNLOOP
778 * 3 ADD TEMP[0], TEMP[0], none.1
779 * 4 ENDLOOP
780 * The Abort flag will be set on instruction 3, because in the first iteration
781 * of the loop it reads the value written by instruction 0 and in all other
782 * iterations it reads the value written by instruction 3.
783 *
784 * @param read_cb This function will be called for for every instruction that
785 * has been determined to be a reader of writer.
786 * @param write_cb This function will be called for every instruction after
787 * writer.
788 */
789 void rc_get_readers(
790 struct radeon_compiler * c,
791 struct rc_instruction * writer,
792 struct rc_reader_data * data,
793 rc_read_src_fn read_normal_cb,
794 rc_pair_read_arg_fn read_pair_cb,
795 rc_read_write_mask_fn write_cb)
796 {
797 struct get_readers_callback_data d;
798
799 data->Abort = 0;
800 data->ReaderCount = 0;
801 data->ReadersReserved = 0;
802 data->Readers = NULL;
803
804 d.C = c;
805 d.ReaderData = data;
806 d.ReadNormalCB = read_normal_cb;
807 d.ReadPairCB = read_pair_cb;
808 d.WriteCB = write_cb;
809
810 rc_for_all_writes_mask(writer, get_readers_for_single_write, &d);
811 }