2 * Copyright (C) 2009 Nicolai Haehnle.
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_program_pair.h"
32 #include "radeon_compiler.h"
33 #include "radeon_dataflow.h"
38 #define DBG(...) do { if (VERBOSE) fprintf(stderr, __VA_ARGS__); } while(0)
41 struct live_intervals
{
44 struct live_intervals
* Next
;
47 struct register_info
{
48 struct live_intervals Live
;
51 unsigned int Allocated
:1;
53 unsigned int Index
:RC_REGISTER_INDEX_BITS
;
56 struct hardware_register
{
57 struct live_intervals
* Used
;
60 struct regalloc_state
{
61 struct radeon_compiler
* C
;
63 struct register_info Input
[RC_REGISTER_MAX_INDEX
];
64 struct register_info Temporary
[RC_REGISTER_MAX_INDEX
];
66 struct hardware_register
* HwTemporary
;
67 unsigned int NumHwTemporaries
;
69 * If an instruction is inside of a loop, EndLoop will be the
70 * IP of the ENDLOOP instruction, and BeginLoop will be the IP
71 * of the BGNLOOP instruction. Otherwise, EndLoop and BeginLoop
78 static void print_live_intervals(struct live_intervals
* src
)
86 DBG("(%i,%i)", src
->Start
, src
->End
);
91 static void add_live_intervals(struct regalloc_state
* s
,
92 struct live_intervals
** dst
, struct live_intervals
* src
)
94 struct live_intervals
** dst_backup
= dst
;
97 DBG("add_live_intervals: ");
98 print_live_intervals(*dst
);
100 print_live_intervals(src
);
105 if (*dst
&& (*dst
)->End
< src
->Start
) {
107 } else if (!*dst
|| (*dst
)->Start
> src
->End
) {
108 struct live_intervals
* li
= memory_pool_malloc(&s
->C
->Pool
, sizeof(*li
));
109 li
->Start
= src
->Start
;
115 if (src
->End
> (*dst
)->End
)
116 (*dst
)->End
= src
->End
;
117 if (src
->Start
< (*dst
)->Start
)
118 (*dst
)->Start
= src
->Start
;
125 print_live_intervals(*dst_backup
);
130 static int overlap_live_intervals(struct live_intervals
* dst
, struct live_intervals
* src
)
133 DBG("overlap_live_intervals: ");
134 print_live_intervals(dst
);
136 print_live_intervals(src
);
141 if (dst
->End
<= src
->Start
) {
143 } else if (dst
->End
<= src
->End
) {
146 } else if (dst
->Start
< src
->End
) {
154 DBG(" no overlap\n");
159 static int try_add_live_intervals(struct regalloc_state
* s
,
160 struct live_intervals
** dst
, struct live_intervals
* src
)
162 if (overlap_live_intervals(*dst
, src
))
165 add_live_intervals(s
, dst
, src
);
169 static void scan_callback(void * data
, struct rc_instruction
* inst
,
170 rc_register_file file
, unsigned int index
, unsigned int mask
)
172 struct regalloc_state
* s
= data
;
173 struct register_info
* reg
;
175 if (file
== RC_FILE_TEMPORARY
)
176 reg
= &s
->Temporary
[index
];
177 else if (file
== RC_FILE_INPUT
)
178 reg
= &s
->Input
[index
];
184 if (file
== RC_FILE_INPUT
)
185 reg
->Live
.Start
= -1;
186 else if (s
->BeginLoop
>= 0)
187 reg
->Live
.Start
= s
->BeginLoop
;
189 reg
->Live
.Start
= inst
->IP
;
190 reg
->Live
.End
= inst
->IP
;
191 } else if (s
->EndLoop
>= 0)
192 reg
->Live
.End
= s
->EndLoop
;
193 else if (inst
->IP
> reg
->Live
.End
)
194 reg
->Live
.End
= inst
->IP
;
197 static void compute_live_intervals(struct radeon_compiler
*c
,
198 struct regalloc_state
*s
)
200 memset(s
, 0, sizeof(*s
));
202 s
->NumHwTemporaries
= c
->max_temp_regs
;
206 memory_pool_malloc(&c
->Pool
,
207 s
->NumHwTemporaries
* sizeof(struct hardware_register
));
208 memset(s
->HwTemporary
, 0, s
->NumHwTemporaries
* sizeof(struct hardware_register
));
210 rc_recompute_ips(s
->C
);
212 for(struct rc_instruction
* inst
= s
->C
->Program
.Instructions
.Next
;
213 inst
!= &s
->C
->Program
.Instructions
;
216 /* For all instructions inside of a loop, the ENDLOOP
217 * instruction is used as the end of the live interval and
218 * the BGNLOOP instruction is used as the beginning. */
219 if (inst
->U
.I
.Opcode
== RC_OPCODE_BGNLOOP
&& s
->EndLoop
< 0) {
220 s
->BeginLoop
= inst
->IP
;
222 struct rc_instruction
* tmp
;
223 for(tmp
= inst
->Next
;
224 tmp
!= &s
->C
->Program
.Instructions
;
226 if (tmp
->U
.I
.Opcode
== RC_OPCODE_BGNLOOP
) {
228 } else if (tmp
->U
.I
.Opcode
229 == RC_OPCODE_ENDLOOP
) {
231 s
->EndLoop
= tmp
->IP
;
238 if (inst
->IP
== s
->EndLoop
) {
243 rc_for_all_reads_mask(inst
, scan_callback
, s
);
244 rc_for_all_writes_mask(inst
, scan_callback
, s
);
248 static void remap_register(void * data
, struct rc_instruction
* inst
,
249 rc_register_file
* file
, unsigned int * index
)
251 struct regalloc_state
* s
= data
;
252 const struct register_info
* reg
;
254 if (*file
== RC_FILE_TEMPORARY
)
255 reg
= &s
->Temporary
[*index
];
256 else if (*file
== RC_FILE_INPUT
)
257 reg
= &s
->Input
[*index
];
261 if (reg
->Allocated
) {
267 static void do_regalloc(struct regalloc_state
* s
)
269 /* Simple and stupid greedy register allocation */
270 for(unsigned int index
= 0; index
< RC_REGISTER_MAX_INDEX
; ++index
) {
271 struct register_info
* reg
= &s
->Temporary
[index
];
276 for(unsigned int hwreg
= 0; hwreg
< s
->NumHwTemporaries
; ++hwreg
) {
277 if (try_add_live_intervals(s
, &s
->HwTemporary
[hwreg
].Used
, ®
->Live
)) {
279 reg
->File
= RC_FILE_TEMPORARY
;
285 rc_error(s
->C
, "Ran out of hardware temporaries\n");
291 /* Rewrite all instructions based on the translation table we built */
292 for(struct rc_instruction
* inst
= s
->C
->Program
.Instructions
.Next
;
293 inst
!= &s
->C
->Program
.Instructions
;
295 rc_remap_registers(inst
, &remap_register
, s
);
299 static void alloc_input(void * data
, unsigned int input
, unsigned int hwreg
)
301 struct regalloc_state
* s
= data
;
303 if (!s
->Input
[input
].Used
)
306 add_live_intervals(s
, &s
->HwTemporary
[hwreg
].Used
, &s
->Input
[input
].Live
);
308 s
->Input
[input
].Allocated
= 1;
309 s
->Input
[input
].File
= RC_FILE_TEMPORARY
;
310 s
->Input
[input
].Index
= hwreg
;
314 void rc_pair_regalloc(struct radeon_compiler
*cc
, void *user
)
316 struct r300_fragment_program_compiler
*c
= (struct r300_fragment_program_compiler
*)cc
;
317 struct regalloc_state s
;
319 compute_live_intervals(cc
, &s
);
321 c
->AllocateHwInputs(c
, &alloc_input
, &s
);
326 /* This functions offsets the temporary register indices by the number
327 * of input registers, because input registers are actually temporaries and
328 * should not occupy the same space.
330 * This pass is supposed to be used to maintain correct allocation of inputs
331 * if the standard register allocation is disabled. */
332 void rc_pair_regalloc_inputs_only(struct radeon_compiler
*cc
, void *user
)
334 struct r300_fragment_program_compiler
*c
= (struct r300_fragment_program_compiler
*)cc
;
335 struct regalloc_state s
;
338 compute_live_intervals(cc
, &s
);
340 c
->AllocateHwInputs(c
, &alloc_input
, &s
);
343 for (unsigned i
= 0; i
< RC_REGISTER_MAX_INDEX
; i
++) {
344 if (s
.Input
[i
].Allocated
&& temp_reg_offset
<= s
.Input
[i
].Index
)
345 temp_reg_offset
= s
.Input
[i
].Index
+ 1;
348 if (temp_reg_offset
) {
349 for (unsigned i
= 0; i
< RC_REGISTER_MAX_INDEX
; i
++) {
350 if (s
.Temporary
[i
].Used
) {
351 s
.Temporary
[i
].Allocated
= 1;
352 s
.Temporary
[i
].File
= RC_FILE_TEMPORARY
;
353 s
.Temporary
[i
].Index
= i
+ temp_reg_offset
;
357 /* Rewrite all registers. */
358 for (struct rc_instruction
*inst
= cc
->Program
.Instructions
.Next
;
359 inst
!= &cc
->Program
.Instructions
;
361 rc_remap_registers(inst
, &remap_register
, &s
);