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