2
* Copyright 2011 Tom Stellard <tstellar@gmail.com>
6
* Permission is hereby granted, free of charge, to any person obtaining
7
* a copy of this software and associated documentation files (the
8
* "Software"), to deal in the Software without restriction, including
9
* without limitation the rights to use, copy, modify, merge, publish,
10
* distribute, sublicense, and/or sell copies of the Software, and to
11
* permit persons to whom the Software is furnished to do so, subject to
12
* the following conditions:
14
* The above copyright notice and this permission notice (including the
15
* next paragraph) shall be included in all copies or substantial
16
* portions of the Software.
18
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
#include "radeon_variable.h"
30
#include "memory_pool.h"
31
#include "radeon_compiler_util.h"
32
#include "radeon_dataflow.h"
33
#include "radeon_list.h"
34
#include "radeon_opcodes.h"
35
#include "radeon_program.h"
38
* Rewrite the index and writemask for the destination register of var
39
* and its friends to new_index and new_writemask. This function also takes
40
* care of rewriting the swizzles for the sources of var.
42
void rc_variable_change_dst(
43
struct rc_variable * var,
44
unsigned int new_index,
45
unsigned int new_writemask)
47
struct rc_variable * var_ptr;
48
struct rc_list * readers;
49
unsigned int old_mask = rc_variable_writemask_sum(var);
50
unsigned int conversion_swizzle =
51
rc_make_conversion_swizzle(old_mask, new_writemask);
53
for (var_ptr = var; var_ptr; var_ptr = var_ptr->Friend) {
54
if (var_ptr->Inst->Type == RC_INSTRUCTION_NORMAL) {
55
rc_normal_rewrite_writemask(var_ptr->Inst,
57
var_ptr->Inst->U.I.DstReg.Index = new_index;
59
struct rc_pair_sub_instruction * sub;
60
if (var_ptr->Dst.WriteMask == RC_MASK_W) {
61
assert(new_writemask & RC_MASK_W);
62
sub = &var_ptr->Inst->U.P.Alpha;
64
sub = &var_ptr->Inst->U.P.RGB;
65
rc_pair_rewrite_writemask(sub,
68
sub->DestIndex = new_index;
72
readers = rc_variable_readers_union(var);
74
for ( ; readers; readers = readers->Next) {
75
struct rc_reader * reader = readers->Item;
76
if (reader->Inst->Type == RC_INSTRUCTION_NORMAL) {
77
reader->U.I.Src->Index = new_index;
78
reader->U.I.Src->Swizzle = rc_rewrite_swizzle(
79
reader->U.I.Src->Swizzle, conversion_swizzle);
81
struct rc_pair_instruction * pair_inst =
83
unsigned int src_type = rc_source_type_swz(
84
reader->U.P.Arg->Swizzle);
86
int src_index = reader->U.P.Arg->Source;
87
if (src_index == RC_PAIR_PRESUB_SRC) {
88
src_index = rc_pair_get_src_index(
89
pair_inst, reader->U.P.Src);
91
/* Try to delete the old src, it is OK if this fails,
92
* because rc_pair_alloc_source might be able to
93
* find a source the ca be reused.
95
if (rc_pair_remove_src(reader->Inst, src_type,
96
src_index, old_mask)) {
97
/* Reuse the source index of the source that
98
* was just deleted and set its register
99
* index. We can't use rc_pair_alloc_source
100
* for this becuase it might return a source
101
* index that is already being used. */
102
if (src_type & RC_SOURCE_RGB) {
103
pair_inst->RGB.Src[src_index]
105
pair_inst->RGB.Src[src_index]
107
pair_inst->RGB.Src[src_index]
108
.File = RC_FILE_TEMPORARY;
110
if (src_type & RC_SOURCE_ALPHA) {
111
pair_inst->Alpha.Src[src_index]
113
pair_inst->Alpha.Src[src_index]
115
pair_inst->Alpha.Src[src_index]
116
.File = RC_FILE_TEMPORARY;
119
src_index = rc_pair_alloc_source(
121
src_type & RC_SOURCE_RGB,
122
src_type & RC_SOURCE_ALPHA,
126
rc_error(var->C, "Rewrite of inst %u failed "
127
"Can't allocate source for "
128
"Inst %u src_type=%x "
129
"new_index=%u new_mask=%u\n",
130
var->Inst->IP, reader->Inst->IP, src_type, new_index, new_writemask);
134
reader->U.P.Arg->Swizzle = rc_rewrite_swizzle(
135
reader->U.P.Arg->Swizzle, conversion_swizzle);
136
if (reader->U.P.Arg->Source != RC_PAIR_PRESUB_SRC) {
137
reader->U.P.Arg->Source = src_index;
144
* Compute the live intervals for var and its friends.
146
void rc_variable_compute_live_intervals(struct rc_variable * var)
150
unsigned int start = var->Inst->IP;
152
for (i = 0; i < var->ReaderCount; i++) {
154
unsigned int chan_start = start;
155
unsigned int chan_end = var->Readers[i].Inst->IP;
156
unsigned int mask = var->Readers[i].WriteMask;
157
struct rc_instruction * inst;
159
/* Extend the live interval of T0 to the start of the
160
* loop for sequences like:
167
if (var->Readers[i].Inst->IP < start) {
168
struct rc_instruction * bgnloop =
169
rc_match_endloop(var->Readers[i].Inst);
170
chan_start = bgnloop->IP;
173
/* Extend the live interval of T0 to the start of the
174
* loop in case there is a BRK instruction in the loop
175
* (we don't actually check for a BRK instruction we
176
* assume there is one somewhere in the loop, which
177
* there usually is) for sequences like:
185
***************************************************
186
* Extend the live interval of T0 to the end of the
187
* loop for sequences like:
194
for (inst = var->Inst; inst != var->Readers[i].Inst;
196
rc_opcode op = rc_get_flow_control_inst(inst);
197
if (op == RC_OPCODE_ENDLOOP) {
198
struct rc_instruction * bgnloop =
199
rc_match_endloop(inst);
200
if (bgnloop->IP < chan_start) {
201
chan_start = bgnloop->IP;
203
} else if (op == RC_OPCODE_BGNLOOP) {
204
struct rc_instruction * endloop =
205
rc_match_bgnloop(inst);
206
if (endloop->IP > chan_end) {
207
chan_end = endloop->IP;
212
for (chan = 0; chan < 4; chan++) {
213
if ((mask >> chan) & 0x1) {
214
if (!var->Live[chan].Used
215
|| chan_start < var->Live[chan].Start) {
216
var->Live[chan].Start =
219
if (!var->Live[chan].Used
220
|| chan_end > var->Live[chan].End) {
221
var->Live[chan].End = chan_end;
223
var->Live[chan].Used = 1;
232
* @return 1 if a and b share a reader
233
* @return 0 if they do not
235
static unsigned int readers_intersect(
236
struct rc_variable * a,
237
struct rc_variable * b)
239
unsigned int a_index, b_index;
240
for (a_index = 0; a_index < a->ReaderCount; a_index++) {
241
struct rc_reader reader_a = a->Readers[a_index];
242
for (b_index = 0; b_index < b->ReaderCount; b_index++) {
243
struct rc_reader reader_b = b->Readers[b_index];
244
if (reader_a.Inst->Type == RC_INSTRUCTION_NORMAL
245
&& reader_b.Inst->Type == RC_INSTRUCTION_NORMAL
246
&& reader_a.U.I.Src == reader_b.U.I.Src) {
250
if (reader_a.Inst->Type == RC_INSTRUCTION_PAIR
251
&& reader_b.Inst->Type == RC_INSTRUCTION_PAIR
252
&& reader_a.U.P.Src == reader_b.U.P.Src) {
261
void rc_variable_add_friend(
262
struct rc_variable * var,
263
struct rc_variable * friend)
265
assert(var->Dst.Index == friend->Dst.Index);
269
var->Friend = friend;
272
struct rc_variable * rc_variable(
273
struct radeon_compiler * c,
274
unsigned int DstFile,
275
unsigned int DstIndex,
276
unsigned int DstWriteMask,
277
struct rc_reader_data * reader_data)
279
struct rc_variable * new =
280
memory_pool_malloc(&c->Pool, sizeof(struct rc_variable));
281
memset(new, 0, sizeof(struct rc_variable));
283
new->Dst.File = DstFile;
284
new->Dst.Index = DstIndex;
285
new->Dst.WriteMask = DstWriteMask;
287
new->Inst = reader_data->Writer;
288
new->ReaderCount = reader_data->ReaderCount;
289
new->Readers = reader_data->Readers;
294
static void get_variable_helper(
295
struct rc_list ** variable_list,
296
struct rc_variable * variable)
298
struct rc_list * list_ptr;
299
for (list_ptr = *variable_list; list_ptr; list_ptr = list_ptr->Next) {
300
if (readers_intersect(variable, list_ptr->Item)) {
301
rc_variable_add_friend(list_ptr->Item, variable);
305
rc_list_add(variable_list, rc_list(&variable->C->Pool, variable));
308
static void get_variable_pair_helper(
309
struct rc_list ** variable_list,
310
struct radeon_compiler * c,
311
struct rc_instruction * inst,
312
struct rc_pair_sub_instruction * sub_inst)
314
struct rc_reader_data reader_data;
315
struct rc_variable * new_var;
316
rc_register_file file;
317
unsigned int writemask;
319
if (sub_inst->Opcode == RC_OPCODE_NOP) {
322
memset(&reader_data, 0, sizeof(struct rc_reader_data));
323
rc_get_readers_sub(c, inst, sub_inst, &reader_data, NULL, NULL, NULL);
325
if (reader_data.ReaderCount == 0) {
329
if (sub_inst->WriteMask) {
330
file = RC_FILE_TEMPORARY;
331
writemask = sub_inst->WriteMask;
332
} else if (sub_inst->OutputWriteMask) {
333
file = RC_FILE_OUTPUT;
334
writemask = sub_inst->OutputWriteMask;
339
new_var = rc_variable(c, file, sub_inst->DestIndex, writemask,
341
get_variable_helper(variable_list, new_var);
345
* Generate a list of variables used by the shader program. Each instruction
346
* that writes to a register is considered a variable. The struct rc_variable
347
* data structure includes a list of readers and is essentially a
348
* definition-use chain. Any two variables that share a reader are considered
349
* "friends" and they are linked together via the Friend attribute.
351
struct rc_list * rc_get_variables(struct radeon_compiler * c)
353
struct rc_instruction * inst;
354
struct rc_list * variable_list = NULL;
356
for (inst = c->Program.Instructions.Next;
357
inst != &c->Program.Instructions;
359
struct rc_reader_data reader_data;
360
struct rc_variable * new_var;
361
memset(&reader_data, 0, sizeof(reader_data));
363
if (inst->Type == RC_INSTRUCTION_NORMAL) {
364
rc_get_readers(c, inst, &reader_data, NULL, NULL, NULL);
365
if (reader_data.ReaderCount == 0) {
368
new_var = rc_variable(c, inst->U.I.DstReg.File,
369
inst->U.I.DstReg.Index,
370
inst->U.I.DstReg.WriteMask, &reader_data);
371
get_variable_helper(&variable_list, new_var);
373
get_variable_pair_helper(&variable_list, c, inst,
375
get_variable_pair_helper(&variable_list, c, inst,
380
return variable_list;
384
* @return The bitwise or of the writemasks of a variable and all of its
387
unsigned int rc_variable_writemask_sum(struct rc_variable * var)
389
unsigned int writemask = 0;
391
writemask |= var->Dst.WriteMask;
398
* @return A list of readers for a variable and its friends. Readers
399
* that read from two different variable friends are only included once in
402
struct rc_list * rc_variable_readers_union(struct rc_variable * var)
404
struct rc_list * list = NULL;
407
for (i = 0; i < var->ReaderCount; i++) {
408
struct rc_list * temp;
409
struct rc_reader * a = &var->Readers[i];
410
unsigned int match = 0;
411
for (temp = list; temp; temp = temp->Next) {
412
struct rc_reader * b = temp->Item;
413
if (a->Inst->Type != b->Inst->Type) {
416
if (a->Inst->Type == RC_INSTRUCTION_NORMAL) {
417
if (a->U.I.Src == b->U.I.Src) {
422
if (a->Inst->Type == RC_INSTRUCTION_PAIR) {
423
if (a->U.P.Arg == b->U.P.Arg
424
&& a->U.P.Src == b->U.P.Src) {
433
rc_list_add(&list, rc_list(&var->C->Pool, a));
440
static unsigned int reader_equals_src(
441
struct rc_reader reader,
442
unsigned int src_type,
445
if (reader.Inst->Type != src_type) {
448
if (src_type == RC_INSTRUCTION_NORMAL) {
449
return reader.U.I.Src == src;
451
return reader.U.P.Src == src;
455
static unsigned int variable_writes_src(
456
struct rc_variable * var,
457
unsigned int src_type,
461
for (i = 0; i < var->ReaderCount; i++) {
462
if (reader_equals_src(var->Readers[i], src_type, src)) {
470
struct rc_list * rc_variable_list_get_writers(
471
struct rc_list * var_list,
472
unsigned int src_type,
475
struct rc_list * list_ptr;
476
struct rc_list * writer_list = NULL;
477
for (list_ptr = var_list; list_ptr; list_ptr = list_ptr->Next) {
478
struct rc_variable * var = list_ptr->Item;
479
if (variable_writes_src(var, src_type, src)) {
480
struct rc_variable * friend;
481
rc_list_add(&writer_list, rc_list(&var->C->Pool, var));
482
for (friend = var->Friend; friend;
483
friend = friend->Friend) {
484
if (variable_writes_src(friend, src_type, src)) {
485
rc_list_add(&writer_list,
486
rc_list(&var->C->Pool, friend));
489
/* Once we have indentifed the variable and its
490
* friends that write this source, we can stop
491
* stop searching, because we know know of the
492
* other variables in the list will write this source.
493
* If they did they would be friends of var.
501
void rc_variable_print(struct rc_variable * var)
505
fprintf(stderr, "%u: TEMP[%u].%u: ",
506
var->Inst->IP, var->Dst.Index, var->Dst.WriteMask);
507
for (i = 0; i < 4; i++) {
508
fprintf(stderr, "chan %u: start=%u end=%u ", i,
509
var->Live[i].Start, var->Live[i].End);
511
fprintf(stderr, "%u readers\n", var->ReaderCount);
513
fprintf(stderr, "Friend: \n\t");