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