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