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