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.
29 #include "radeon_variable.h"
31 #include "memory_pool.h"
32 #include "radeon_compiler_util.h"
33 #include "radeon_dataflow.h"
34 #include "radeon_list.h"
35 #include "radeon_opcodes.h"
36 #include "radeon_program.h"
39 * Rewrite the index and writemask for the destination register of var
40 * and its friends to new_index and new_writemask. This function also takes
41 * care of rewriting the swizzles for the sources of var.
43 void rc_variable_change_dst(
44 struct rc_variable
* var
,
45 unsigned int new_index
,
46 unsigned int new_writemask
)
48 struct rc_variable
* var_ptr
;
49 struct rc_list
* readers
;
50 unsigned int old_mask
= rc_variable_writemask_sum(var
);
51 unsigned int conversion_swizzle
=
52 rc_make_conversion_swizzle(old_mask
, new_writemask
);
54 for (var_ptr
= var
; var_ptr
; var_ptr
= var_ptr
->Friend
) {
55 if (var_ptr
->Inst
->Type
== RC_INSTRUCTION_NORMAL
) {
56 rc_normal_rewrite_writemask(var_ptr
->Inst
,
58 var_ptr
->Inst
->U
.I
.DstReg
.Index
= new_index
;
60 struct rc_pair_sub_instruction
* sub
;
61 if (var_ptr
->Dst
.WriteMask
== RC_MASK_W
) {
62 assert(new_writemask
& RC_MASK_W
);
63 sub
= &var_ptr
->Inst
->U
.P
.Alpha
;
65 sub
= &var_ptr
->Inst
->U
.P
.RGB
;
66 rc_pair_rewrite_writemask(sub
,
69 sub
->DestIndex
= new_index
;
73 readers
= rc_variable_readers_union(var
);
75 for ( ; readers
; readers
= readers
->Next
) {
76 struct rc_reader
* reader
= readers
->Item
;
77 if (reader
->Inst
->Type
== RC_INSTRUCTION_NORMAL
) {
78 reader
->U
.I
.Src
->Index
= new_index
;
79 reader
->U
.I
.Src
->Swizzle
= rc_rewrite_swizzle(
80 reader
->U
.I
.Src
->Swizzle
, conversion_swizzle
);
82 struct rc_pair_instruction
* pair_inst
=
84 unsigned int src_type
= rc_source_type_swz(
85 reader
->U
.P
.Arg
->Swizzle
);
87 int src_index
= reader
->U
.P
.Arg
->Source
;
88 if (src_index
== RC_PAIR_PRESUB_SRC
) {
89 src_index
= rc_pair_get_src_index(
90 pair_inst
, reader
->U
.P
.Src
);
92 /* Try to delete the old src, it is OK if this fails,
93 * because rc_pair_alloc_source might be able to
94 * find a source the ca be reused.
96 if (rc_pair_remove_src(reader
->Inst
, src_type
,
97 src_index
, old_mask
)) {
98 /* Reuse the source index of the source that
99 * was just deleted and set its register
100 * index. We can't use rc_pair_alloc_source
101 * for this because it might return a source
102 * index that is already being used. */
103 if (src_type
& RC_SOURCE_RGB
) {
104 pair_inst
->RGB
.Src
[src_index
]
106 pair_inst
->RGB
.Src
[src_index
]
108 pair_inst
->RGB
.Src
[src_index
]
109 .File
= RC_FILE_TEMPORARY
;
111 if (src_type
& RC_SOURCE_ALPHA
) {
112 pair_inst
->Alpha
.Src
[src_index
]
114 pair_inst
->Alpha
.Src
[src_index
]
116 pair_inst
->Alpha
.Src
[src_index
]
117 .File
= RC_FILE_TEMPORARY
;
120 src_index
= rc_pair_alloc_source(
122 src_type
& RC_SOURCE_RGB
,
123 src_type
& RC_SOURCE_ALPHA
,
127 rc_error(var
->C
, "Rewrite of inst %u failed "
128 "Can't allocate source for "
129 "Inst %u src_type=%x "
130 "new_index=%u new_mask=%u\n",
131 var
->Inst
->IP
, reader
->Inst
->IP
, src_type
, new_index
, new_writemask
);
135 reader
->U
.P
.Arg
->Swizzle
= rc_rewrite_swizzle(
136 reader
->U
.P
.Arg
->Swizzle
, conversion_swizzle
);
137 if (reader
->U
.P
.Arg
->Source
!= RC_PAIR_PRESUB_SRC
) {
138 reader
->U
.P
.Arg
->Source
= src_index
;
145 * Compute the live intervals for var and its friends.
147 void rc_variable_compute_live_intervals(struct rc_variable
* var
)
151 unsigned int start
= var
->Inst
->IP
;
153 for (i
= 0; i
< var
->ReaderCount
; i
++) {
155 unsigned int chan_start
= start
;
156 unsigned int chan_end
= var
->Readers
[i
].Inst
->IP
;
157 unsigned int mask
= var
->Readers
[i
].WriteMask
;
158 struct rc_instruction
* inst
;
160 /* Extend the live interval of T0 to the start of the
161 * loop for sequences like:
168 if (var
->Readers
[i
].Inst
->IP
< start
) {
169 struct rc_instruction
* bgnloop
=
170 rc_match_endloop(var
->Readers
[i
].Inst
);
171 chan_start
= bgnloop
->IP
;
174 /* Extend the live interval of T0 to the start of the
175 * loop in case there is a BRK instruction in the loop
176 * (we don't actually check for a BRK instruction we
177 * assume there is one somewhere in the loop, which
178 * there usually is) for sequences like:
186 ***************************************************
187 * Extend the live interval of T0 to the end of the
188 * loop for sequences like:
195 for (inst
= var
->Inst
; inst
!= var
->Readers
[i
].Inst
;
197 rc_opcode op
= rc_get_flow_control_inst(inst
);
198 if (op
== RC_OPCODE_ENDLOOP
) {
199 struct rc_instruction
* bgnloop
=
200 rc_match_endloop(inst
);
201 if (bgnloop
->IP
< chan_start
) {
202 chan_start
= bgnloop
->IP
;
204 } else if (op
== RC_OPCODE_BGNLOOP
) {
205 struct rc_instruction
* endloop
=
206 rc_match_bgnloop(inst
);
207 if (endloop
->IP
> chan_end
) {
208 chan_end
= endloop
->IP
;
213 for (chan
= 0; chan
< 4; chan
++) {
214 if ((mask
>> chan
) & 0x1) {
215 if (!var
->Live
[chan
].Used
216 || chan_start
< var
->Live
[chan
].Start
) {
217 var
->Live
[chan
].Start
=
220 if (!var
->Live
[chan
].Used
221 || chan_end
> var
->Live
[chan
].End
) {
222 var
->Live
[chan
].End
= chan_end
;
224 var
->Live
[chan
].Used
= 1;
233 * @return 1 if a and b share a reader
234 * @return 0 if they do not
236 static unsigned int readers_intersect(
237 struct rc_variable
* a
,
238 struct rc_variable
* b
)
240 unsigned int a_index
, b_index
;
241 for (a_index
= 0; a_index
< a
->ReaderCount
; a_index
++) {
242 struct rc_reader reader_a
= a
->Readers
[a_index
];
243 for (b_index
= 0; b_index
< b
->ReaderCount
; b_index
++) {
244 struct rc_reader reader_b
= b
->Readers
[b_index
];
245 if (reader_a
.Inst
->Type
== RC_INSTRUCTION_NORMAL
246 && reader_b
.Inst
->Type
== RC_INSTRUCTION_NORMAL
247 && reader_a
.U
.I
.Src
== reader_b
.U
.I
.Src
) {
251 if (reader_a
.Inst
->Type
== RC_INSTRUCTION_PAIR
252 && reader_b
.Inst
->Type
== RC_INSTRUCTION_PAIR
253 && reader_a
.U
.P
.Src
== reader_b
.U
.P
.Src
) {
262 void rc_variable_add_friend(
263 struct rc_variable
* var
,
264 struct rc_variable
* friend)
266 assert(var
->Dst
.Index
== friend->Dst
.Index
);
270 var
->Friend
= friend;
273 struct rc_variable
* rc_variable(
274 struct radeon_compiler
* c
,
275 unsigned int DstFile
,
276 unsigned int DstIndex
,
277 unsigned int DstWriteMask
,
278 struct rc_reader_data
* reader_data
)
280 struct rc_variable
* new =
281 memory_pool_malloc(&c
->Pool
, sizeof(struct rc_variable
));
282 memset(new, 0, sizeof(struct rc_variable
));
284 new->Dst
.File
= DstFile
;
285 new->Dst
.Index
= DstIndex
;
286 new->Dst
.WriteMask
= DstWriteMask
;
288 new->Inst
= reader_data
->Writer
;
289 new->ReaderCount
= reader_data
->ReaderCount
;
290 new->Readers
= reader_data
->Readers
;
295 static void get_variable_helper(
296 struct rc_list
** variable_list
,
297 struct rc_variable
* variable
)
299 struct rc_list
* list_ptr
;
300 for (list_ptr
= *variable_list
; list_ptr
; list_ptr
= list_ptr
->Next
) {
301 struct rc_variable
* var
;
302 for (var
= list_ptr
->Item
; var
; var
= var
->Friend
) {
303 if (readers_intersect(var
, variable
)) {
304 rc_variable_add_friend(var
, variable
);
309 rc_list_add(variable_list
, rc_list(&variable
->C
->Pool
, variable
));
312 static void get_variable_pair_helper(
313 struct rc_list
** variable_list
,
314 struct radeon_compiler
* c
,
315 struct rc_instruction
* inst
,
316 struct rc_pair_sub_instruction
* sub_inst
)
318 struct rc_reader_data reader_data
;
319 struct rc_variable
* new_var
;
320 rc_register_file file
;
321 unsigned int writemask
;
323 if (sub_inst
->Opcode
== RC_OPCODE_NOP
) {
326 memset(&reader_data
, 0, sizeof(struct rc_reader_data
));
327 rc_get_readers_sub(c
, inst
, sub_inst
, &reader_data
, NULL
, NULL
, NULL
);
329 if (reader_data
.ReaderCount
== 0) {
333 if (sub_inst
->WriteMask
) {
334 file
= RC_FILE_TEMPORARY
;
335 writemask
= sub_inst
->WriteMask
;
336 } else if (sub_inst
->OutputWriteMask
) {
337 file
= RC_FILE_OUTPUT
;
338 writemask
= sub_inst
->OutputWriteMask
;
343 new_var
= rc_variable(c
, file
, sub_inst
->DestIndex
, writemask
,
345 get_variable_helper(variable_list
, new_var
);
349 * Generate a list of variables used by the shader program. Each instruction
350 * that writes to a register is considered a variable. The struct rc_variable
351 * data structure includes a list of readers and is essentially a
352 * definition-use chain. Any two variables that share a reader are considered
353 * "friends" and they are linked together via the Friend attribute.
355 struct rc_list
* rc_get_variables(struct radeon_compiler
* c
)
357 struct rc_instruction
* inst
;
358 struct rc_list
* variable_list
= NULL
;
360 for (inst
= c
->Program
.Instructions
.Next
;
361 inst
!= &c
->Program
.Instructions
;
363 struct rc_reader_data reader_data
;
364 struct rc_variable
* new_var
;
365 memset(&reader_data
, 0, sizeof(reader_data
));
367 if (inst
->Type
== RC_INSTRUCTION_NORMAL
) {
368 rc_get_readers(c
, inst
, &reader_data
, NULL
, NULL
, NULL
);
369 if (reader_data
.ReaderCount
== 0) {
372 new_var
= rc_variable(c
, inst
->U
.I
.DstReg
.File
,
373 inst
->U
.I
.DstReg
.Index
,
374 inst
->U
.I
.DstReg
.WriteMask
, &reader_data
);
375 get_variable_helper(&variable_list
, new_var
);
377 get_variable_pair_helper(&variable_list
, c
, inst
,
379 get_variable_pair_helper(&variable_list
, c
, inst
,
384 return variable_list
;
388 * @return The bitwise or of the writemasks of a variable and all of its
391 unsigned int rc_variable_writemask_sum(struct rc_variable
* var
)
393 unsigned int writemask
= 0;
395 writemask
|= var
->Dst
.WriteMask
;
402 * @return A list of readers for a variable and its friends. Readers
403 * that read from two different variable friends are only included once in
406 struct rc_list
* rc_variable_readers_union(struct rc_variable
* var
)
408 struct rc_list
* list
= NULL
;
411 for (i
= 0; i
< var
->ReaderCount
; i
++) {
412 struct rc_list
* temp
;
413 struct rc_reader
* a
= &var
->Readers
[i
];
414 unsigned int match
= 0;
415 for (temp
= list
; temp
; temp
= temp
->Next
) {
416 struct rc_reader
* b
= temp
->Item
;
417 if (a
->Inst
->Type
!= b
->Inst
->Type
) {
420 if (a
->Inst
->Type
== RC_INSTRUCTION_NORMAL
) {
421 if (a
->U
.I
.Src
== b
->U
.I
.Src
) {
426 if (a
->Inst
->Type
== RC_INSTRUCTION_PAIR
) {
427 if (a
->U
.P
.Arg
== b
->U
.P
.Arg
428 && a
->U
.P
.Src
== b
->U
.P
.Src
) {
437 rc_list_add(&list
, rc_list(&var
->C
->Pool
, a
));
444 static unsigned int reader_equals_src(
445 struct rc_reader reader
,
446 unsigned int src_type
,
449 if (reader
.Inst
->Type
!= src_type
) {
452 if (src_type
== RC_INSTRUCTION_NORMAL
) {
453 return reader
.U
.I
.Src
== src
;
455 return reader
.U
.P
.Src
== src
;
459 static unsigned int variable_writes_src(
460 struct rc_variable
* var
,
461 unsigned int src_type
,
465 for (i
= 0; i
< var
->ReaderCount
; i
++) {
466 if (reader_equals_src(var
->Readers
[i
], src_type
, src
)) {
474 struct rc_list
* rc_variable_list_get_writers(
475 struct rc_list
* var_list
,
476 unsigned int src_type
,
479 struct rc_list
* list_ptr
;
480 struct rc_list
* writer_list
= NULL
;
481 for (list_ptr
= var_list
; list_ptr
; list_ptr
= list_ptr
->Next
) {
482 struct rc_variable
* var
= list_ptr
->Item
;
483 if (variable_writes_src(var
, src_type
, src
)) {
484 struct rc_variable
* friend;
485 rc_list_add(&writer_list
, rc_list(&var
->C
->Pool
, var
));
486 for (friend = var
->Friend
; friend;
487 friend = friend->Friend
) {
488 if (variable_writes_src(friend, src_type
, src
)) {
489 rc_list_add(&writer_list
,
490 rc_list(&var
->C
->Pool
, friend));
493 /* Once we have indentifed the variable and its
494 * friends that write this source, we can stop
495 * stop searching, because we know none of the
496 * other variables in the list will write this source.
497 * If they did they would be friends of var.
505 struct rc_list
* rc_variable_list_get_writers_one_reader(
506 struct rc_list
* var_list
,
507 unsigned int src_type
,
510 struct rc_list
* writer_list
=
511 rc_variable_list_get_writers(var_list
, src_type
, src
);
512 struct rc_list
* reader_list
=
513 rc_variable_readers_union(writer_list
->Item
);
514 if (rc_list_count(reader_list
) > 1) {
521 void rc_variable_print(struct rc_variable
* var
)
525 fprintf(stderr
, "%u: TEMP[%u].%u: ",
526 var
->Inst
->IP
, var
->Dst
.Index
, var
->Dst
.WriteMask
);
527 for (i
= 0; i
< 4; i
++) {
528 fprintf(stderr
, "chan %u: start=%u end=%u ", i
,
529 var
->Live
[i
].Start
, var
->Live
[i
].End
);
531 fprintf(stderr
, "%u readers\n", var
->ReaderCount
);
533 fprintf(stderr
, "Friend: \n\t");