• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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