Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/r300/compiler/radeon_dataflow.c
4574 views
1
/*
2
* Copyright (C) 2009 Nicolai Haehnle.
3
* Copyright 2010 Tom Stellard <[email protected]>
4
*
5
* All Rights Reserved.
6
*
7
* Permission is hereby granted, free of charge, to any person obtaining
8
* a copy of this software and associated documentation files (the
9
* "Software"), to deal in the Software without restriction, including
10
* without limitation the rights to use, copy, modify, merge, publish,
11
* distribute, sublicense, and/or sell copies of the Software, and to
12
* permit persons to whom the Software is furnished to do so, subject to
13
* the following conditions:
14
*
15
* The above copyright notice and this permission notice (including the
16
* next paragraph) shall be included in all copies or substantial
17
* portions of the Software.
18
*
19
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
23
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
*
27
*/
28
29
#include "radeon_dataflow.h"
30
31
#include "radeon_compiler.h"
32
#include "radeon_compiler_util.h"
33
#include "radeon_program.h"
34
35
struct read_write_mask_data {
36
void * UserData;
37
rc_read_write_mask_fn Cb;
38
};
39
40
static void reads_normal_callback(
41
void * userdata,
42
struct rc_instruction * fullinst,
43
struct rc_src_register * src)
44
{
45
struct read_write_mask_data * cb_data = userdata;
46
unsigned int refmask = 0;
47
unsigned int chan;
48
for(chan = 0; chan < 4; chan++) {
49
refmask |= 1 << GET_SWZ(src->Swizzle, chan);
50
}
51
refmask &= RC_MASK_XYZW;
52
53
if (refmask) {
54
cb_data->Cb(cb_data->UserData, fullinst, src->File,
55
src->Index, refmask);
56
}
57
58
if (refmask && src->RelAddr) {
59
cb_data->Cb(cb_data->UserData, fullinst, RC_FILE_ADDRESS, 0,
60
RC_MASK_X);
61
}
62
}
63
64
static void pair_get_src_refmasks(unsigned int * refmasks,
65
struct rc_pair_instruction * inst,
66
unsigned int swz, unsigned int src)
67
{
68
if (swz >= 4)
69
return;
70
71
if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y || swz == RC_SWIZZLE_Z) {
72
if(src == RC_PAIR_PRESUB_SRC) {
73
unsigned int i;
74
int srcp_regs =
75
rc_presubtract_src_reg_count(
76
inst->RGB.Src[src].Index);
77
for(i = 0; i < srcp_regs; i++) {
78
refmasks[i] |= 1 << swz;
79
}
80
}
81
else {
82
refmasks[src] |= 1 << swz;
83
}
84
}
85
86
if (swz == RC_SWIZZLE_W) {
87
if (src == RC_PAIR_PRESUB_SRC) {
88
unsigned int i;
89
int srcp_regs = rc_presubtract_src_reg_count(
90
inst->Alpha.Src[src].Index);
91
for(i = 0; i < srcp_regs; i++) {
92
refmasks[i] |= 1 << swz;
93
}
94
}
95
else {
96
refmasks[src] |= 1 << swz;
97
}
98
}
99
}
100
101
static void reads_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
102
{
103
struct rc_pair_instruction * inst = &fullinst->U.P;
104
unsigned int refmasks[3] = { 0, 0, 0 };
105
106
unsigned int arg;
107
108
for(arg = 0; arg < 3; ++arg) {
109
unsigned int chan;
110
for(chan = 0; chan < 3; ++chan) {
111
unsigned int swz_rgb =
112
GET_SWZ(inst->RGB.Arg[arg].Swizzle, chan);
113
unsigned int swz_alpha =
114
GET_SWZ(inst->Alpha.Arg[arg].Swizzle, chan);
115
pair_get_src_refmasks(refmasks, inst, swz_rgb,
116
inst->RGB.Arg[arg].Source);
117
pair_get_src_refmasks(refmasks, inst, swz_alpha,
118
inst->Alpha.Arg[arg].Source);
119
}
120
}
121
122
for(unsigned int src = 0; src < 3; ++src) {
123
if (inst->RGB.Src[src].Used && (refmasks[src] & RC_MASK_XYZ))
124
cb(userdata, fullinst, inst->RGB.Src[src].File, inst->RGB.Src[src].Index,
125
refmasks[src] & RC_MASK_XYZ);
126
127
if (inst->Alpha.Src[src].Used && (refmasks[src] & RC_MASK_W))
128
cb(userdata, fullinst, inst->Alpha.Src[src].File, inst->Alpha.Src[src].Index, RC_MASK_W);
129
}
130
}
131
132
static void pair_sub_for_all_args(
133
struct rc_instruction * fullinst,
134
struct rc_pair_sub_instruction * sub,
135
rc_pair_read_arg_fn cb,
136
void * userdata)
137
{
138
int i;
139
const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode);
140
141
for(i = 0; i < info->NumSrcRegs; i++) {
142
unsigned int src_type;
143
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
* */
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
*/
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
*/
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
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
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
*/
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
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
*/
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
*/
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
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
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
*/
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
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
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
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
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
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
*/
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
*/
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
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
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
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
struct get_readers_callback_data * d = userdata;
692
693
d->ReaderData->Writer = writer;
694
d->ReaderData->AbortOnRead = 0;
695
d->ReaderData->AbortOnWrite = 0;
696
d->ReaderData->LoopDepth = 0;
697
d->ReaderData->InElse = 0;
698
d->DstFile = dst_file;
699
d->DstIndex = dst_index;
700
d->DstMask = dst_mask;
701
d->AliveWriteMask = dst_mask;
702
memset(d->BranchMasks, 0, sizeof(d->BranchMasks));
703
704
if (!dst_mask)
705
return;
706
707
for(tmp = writer->Next; tmp != &d->C->Program.Instructions;
708
tmp = tmp->Next){
709
rc_opcode opcode = rc_get_flow_control_inst(tmp);
710
switch(opcode) {
711
case RC_OPCODE_BGNLOOP:
712
d->ReaderData->LoopDepth++;
713
push_branch_mask(d, &branch_depth);
714
break;
715
case RC_OPCODE_ENDLOOP:
716
if (d->ReaderData->LoopDepth > 0) {
717
d->ReaderData->LoopDepth--;
718
if (d->ReaderData->LoopDepth == 0) {
719
d->ReaderData->AbortOnWrite = 0;
720
}
721
pop_branch_mask(d, &branch_depth);
722
} else {
723
/* Here we have reached an ENDLOOP without
724
* seeing its BGNLOOP. These means that
725
* the writer was written inside of a loop,
726
* so it could have readers that are above it
727
* (i.e. they have a lower IP). To find these
728
* readers we jump to the BGNLOOP instruction
729
* and check each instruction until we get
730
* back to the writer.
731
*/
732
endloop = tmp;
733
tmp = rc_match_endloop(tmp);
734
if (!tmp) {
735
rc_error(d->C, "Failed to match endloop.\n");
736
d->ReaderData->Abort = 1;
737
return;
738
}
739
abort_on_read_at_endloop = d->ReaderData->AbortOnRead;
740
d->ReaderData->AbortOnRead |= d->AliveWriteMask;
741
continue;
742
}
743
break;
744
case RC_OPCODE_IF:
745
push_branch_mask(d, &branch_depth);
746
break;
747
case RC_OPCODE_ELSE:
748
if (branch_depth == 0) {
749
d->ReaderData->InElse = 1;
750
} else {
751
unsigned int temp_mask = d->AliveWriteMask;
752
d->AliveWriteMask =
753
d->BranchMasks[branch_depth].IfWriteMask;
754
d->BranchMasks[branch_depth].ElseWriteMask =
755
temp_mask;
756
d->BranchMasks[branch_depth].HasElse = 1;
757
}
758
break;
759
case RC_OPCODE_ENDIF:
760
if (branch_depth == 0) {
761
d->ReaderData->AbortOnRead = d->AliveWriteMask;
762
d->ReaderData->InElse = 0;
763
}
764
else {
765
pop_branch_mask(d, &branch_depth);
766
}
767
break;
768
default:
769
break;
770
}
771
772
if (d->ReaderData->InElse)
773
continue;
774
775
if (tmp->Type == RC_INSTRUCTION_NORMAL) {
776
rc_for_all_reads_src(tmp,
777
get_readers_normal_read_callback, d);
778
} else {
779
rc_pair_for_all_reads_arg(tmp,
780
get_readers_pair_read_callback, d);
781
}
782
783
/* This can happen when we jump from an ENDLOOP to BGNLOOP */
784
if (tmp == writer) {
785
tmp = endloop;
786
endloop = NULL;
787
d->ReaderData->AbortOnRead = abort_on_read_at_endloop;
788
continue;
789
}
790
rc_for_all_writes_mask(tmp, get_readers_write_callback, d);
791
792
if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort)
793
return;
794
795
if (branch_depth == 0 && !d->AliveWriteMask)
796
return;
797
}
798
}
799
800
static void init_get_readers_callback_data(
801
struct get_readers_callback_data * d,
802
struct rc_reader_data * reader_data,
803
struct radeon_compiler * c,
804
rc_read_src_fn read_normal_cb,
805
rc_pair_read_arg_fn read_pair_cb,
806
rc_read_write_mask_fn write_cb)
807
{
808
reader_data->Abort = 0;
809
reader_data->ReaderCount = 0;
810
reader_data->ReadersReserved = 0;
811
reader_data->Readers = NULL;
812
813
d->C = c;
814
d->ReaderData = reader_data;
815
d->ReadNormalCB = read_normal_cb;
816
d->ReadPairCB = read_pair_cb;
817
d->WriteCB = write_cb;
818
}
819
820
/**
821
* This function will create a list of readers via the rc_reader_data struct.
822
* This function will abort (set the flag data->Abort) and return if it
823
* encounters an instruction that reads from @param writer and also a different
824
* instruction. Here are some examples:
825
*
826
* writer = instruction 0;
827
* 0 MOV TEMP[0].xy, TEMP[1].xy
828
* 1 MOV TEMP[0].zw, TEMP[2].xy
829
* 2 MOV TEMP[3], TEMP[0]
830
* The Abort flag will be set on instruction 2, because it reads values written
831
* by instructions 0 and 1.
832
*
833
* writer = instruction 1;
834
* 0 IF TEMP[0].x
835
* 1 MOV TEMP[1], TEMP[2]
836
* 2 ELSE
837
* 3 MOV TEMP[1], TEMP[2]
838
* 4 ENDIF
839
* 5 MOV TEMP[3], TEMP[1]
840
* The Abort flag will be set on instruction 5, because it could read from the
841
* value written by either instruction 1 or 3, depending on the jump decision
842
* made at instruction 0.
843
*
844
* writer = instruction 0;
845
* 0 MOV TEMP[0], TEMP[1]
846
* 2 BGNLOOP
847
* 3 ADD TEMP[0], TEMP[0], none.1
848
* 4 ENDLOOP
849
* The Abort flag will be set on instruction 3, because in the first iteration
850
* of the loop it reads the value written by instruction 0 and in all other
851
* iterations it reads the value written by instruction 3.
852
*
853
* @param read_cb This function will be called for every instruction that
854
* has been determined to be a reader of writer.
855
* @param write_cb This function will be called for every instruction after
856
* writer.
857
*/
858
void rc_get_readers(
859
struct radeon_compiler * c,
860
struct rc_instruction * writer,
861
struct rc_reader_data * data,
862
rc_read_src_fn read_normal_cb,
863
rc_pair_read_arg_fn read_pair_cb,
864
rc_read_write_mask_fn write_cb)
865
{
866
struct get_readers_callback_data d;
867
868
init_get_readers_callback_data(&d, data, c, read_normal_cb,
869
read_pair_cb, write_cb);
870
871
rc_for_all_writes_mask(writer, get_readers_for_single_write, &d);
872
}
873
874
void rc_get_readers_sub(
875
struct radeon_compiler * c,
876
struct rc_instruction * writer,
877
struct rc_pair_sub_instruction * sub_writer,
878
struct rc_reader_data * data,
879
rc_read_src_fn read_normal_cb,
880
rc_pair_read_arg_fn read_pair_cb,
881
rc_read_write_mask_fn write_cb)
882
{
883
struct get_readers_callback_data d;
884
885
init_get_readers_callback_data(&d, data, c, read_normal_cb,
886
read_pair_cb, write_cb);
887
888
if (sub_writer->WriteMask) {
889
get_readers_for_single_write(&d, writer, RC_FILE_TEMPORARY,
890
sub_writer->DestIndex, sub_writer->WriteMask);
891
}
892
}
893
894