Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / drivers / dri / r300 / compiler / radeon_pair_regalloc.c
1 /*
2  * Copyright (C) 2009 Nicolai Haehnle.
3  * Copyright 2011 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_program_pair.h"
30
31 #include <stdio.h>
32
33 #include "main/glheader.h"
34 #include "program/register_allocate.h"
35 #include "ralloc.h"
36
37 #include "r300_fragprog_swizzle.h"
38 #include "radeon_compiler.h"
39 #include "radeon_compiler_util.h"
40 #include "radeon_dataflow.h"
41 #include "radeon_list.h"
42 #include "radeon_variable.h"
43
44 #define VERBOSE 0
45
46 #define DBG(...) do { if (VERBOSE) fprintf(stderr, __VA_ARGS__); } while(0)
47
48
49
50 struct register_info {
51         struct live_intervals Live[4];
52
53         unsigned int Used:1;
54         unsigned int Allocated:1;
55         unsigned int File:3;
56         unsigned int Index:RC_REGISTER_INDEX_BITS;
57         unsigned int Writemask;
58 };
59
60 struct regalloc_state {
61         struct radeon_compiler * C;
62
63         struct register_info * Input;
64         unsigned int NumInputs;
65
66         struct register_info * Temporary;
67         unsigned int NumTemporaries;
68
69         unsigned int Simple;
70         int LoopEnd;
71 };
72
73 enum rc_reg_class {
74         RC_REG_CLASS_SINGLE,
75         RC_REG_CLASS_DOUBLE,
76         RC_REG_CLASS_TRIPLE,
77         RC_REG_CLASS_ALPHA,
78         RC_REG_CLASS_SINGLE_PLUS_ALPHA,
79         RC_REG_CLASS_DOUBLE_PLUS_ALPHA,
80         RC_REG_CLASS_TRIPLE_PLUS_ALPHA,
81         RC_REG_CLASS_X,
82         RC_REG_CLASS_Y,
83         RC_REG_CLASS_Z,
84         RC_REG_CLASS_XY,
85         RC_REG_CLASS_YZ,
86         RC_REG_CLASS_XZ,
87         RC_REG_CLASS_XW,
88         RC_REG_CLASS_YW,
89         RC_REG_CLASS_ZW,
90         RC_REG_CLASS_XYW,
91         RC_REG_CLASS_YZW,
92         RC_REG_CLASS_XZW,
93         RC_REG_CLASS_COUNT
94 };
95
96 struct rc_class {
97         enum rc_reg_class Class;
98
99         unsigned int WritemaskCount;
100
101         /** This is 1 if this class is being used by the register allocator
102          * and 0 otherwise */
103         unsigned int Used;
104
105         /** This is the ID number assigned to this class by ra. */
106         unsigned int Id;
107
108         /** List of writemasks that belong to this class */
109         unsigned int Writemasks[3];
110
111
112 };
113
114 static void print_live_intervals(struct live_intervals * src)
115 {
116         if (!src || !src->Used) {
117                 DBG("(null)");
118                 return;
119         }
120
121         DBG("(%i,%i)", src->Start, src->End);
122 }
123
124 static int overlap_live_intervals(struct live_intervals * a, struct live_intervals * b)
125 {
126         if (VERBOSE) {
127                 DBG("overlap_live_intervals: ");
128                 print_live_intervals(a);
129                 DBG(" to ");
130                 print_live_intervals(b);
131                 DBG("\n");
132         }
133
134         if (!a->Used || !b->Used) {
135                 DBG("    unused interval\n");
136                 return 0;
137         }
138
139         if (a->Start > b->Start) {
140                 if (a->Start < b->End) {
141                         DBG("    overlap\n");
142                         return 1;
143                 }
144         } else if (b->Start > a->Start) {
145                 if (b->Start < a->End) {
146                         DBG("    overlap\n");
147                         return 1;
148                 }
149         } else { /* a->Start == b->Start */
150                 if (a->Start != a->End && b->Start != b->End) {
151                         DBG("    overlap\n");
152                         return 1;
153                 }
154         }
155
156         DBG("    no overlap\n");
157
158         return 0;
159 }
160
161 static void scan_read_callback(void * data, struct rc_instruction * inst,
162                 rc_register_file file, unsigned int index, unsigned int mask)
163 {
164         struct regalloc_state * s = data;
165         struct register_info * reg;
166         unsigned int i;
167
168         if (file != RC_FILE_INPUT)
169                 return;
170
171         s->Input[index].Used = 1;
172         reg = &s->Input[index];
173
174         for (i = 0; i < 4; i++) {
175                 if (!((mask >> i) & 0x1)) {
176                         continue;
177                 }
178                 reg->Live[i].Used = 1;
179                 reg->Live[i].Start = 0;
180                 reg->Live[i].End =
181                         s->LoopEnd > inst->IP ? s->LoopEnd : inst->IP;
182         }
183 }
184
185 static void remap_register(void * data, struct rc_instruction * inst,
186                 rc_register_file * file, unsigned int * index)
187 {
188         struct regalloc_state * s = data;
189         const struct register_info * reg;
190
191         if (*file == RC_FILE_TEMPORARY && s->Simple)
192                 reg = &s->Temporary[*index];
193         else if (*file == RC_FILE_INPUT)
194                 reg = &s->Input[*index];
195         else
196                 return;
197
198         if (reg->Allocated) {
199                 *index = reg->Index;
200         }
201 }
202
203 static void alloc_input_simple(void * data, unsigned int input,
204                                                         unsigned int hwreg)
205 {
206         struct regalloc_state * s = data;
207
208         if (input >= s->NumInputs)
209                 return;
210
211         s->Input[input].Allocated = 1;
212         s->Input[input].File = RC_FILE_TEMPORARY;
213         s->Input[input].Index = hwreg;
214 }
215
216 /* This functions offsets the temporary register indices by the number
217  * of input registers, because input registers are actually temporaries and
218  * should not occupy the same space.
219  *
220  * This pass is supposed to be used to maintain correct allocation of inputs
221  * if the standard register allocation is disabled. */
222 static void do_regalloc_inputs_only(struct regalloc_state * s)
223 {
224         for (unsigned i = 0; i < s->NumTemporaries; i++) {
225                 s->Temporary[i].Allocated = 1;
226                 s->Temporary[i].File = RC_FILE_TEMPORARY;
227                 s->Temporary[i].Index = i + s->NumInputs;
228         }
229 }
230
231 static unsigned int is_derivative(rc_opcode op)
232 {
233         return (op == RC_OPCODE_DDX || op == RC_OPCODE_DDY);
234 }
235
236 static int find_class(
237         struct rc_class * classes,
238         unsigned int writemask,
239         unsigned int max_writemask_count)
240 {
241         unsigned int i;
242         for (i = 0; i < RC_REG_CLASS_COUNT; i++) {
243                 unsigned int j;
244                 if (classes[i].WritemaskCount > max_writemask_count) {
245                         continue;
246                 }
247                 for (j = 0; j < 3; j++) {
248                         if (classes[i].Writemasks[j] == writemask) {
249                                 return i;
250                         }
251                 }
252         }
253         return -1;
254 }
255
256 static enum rc_reg_class variable_get_class(
257         struct rc_variable * variable,
258         struct rc_class * classes)
259 {
260         unsigned int i;
261         unsigned int can_change_writemask= 1;
262         unsigned int writemask = rc_variable_writemask_sum(variable);
263         struct rc_list * readers = rc_variable_readers_union(variable);
264         int class_index;
265
266         if (!variable->C->is_r500) {
267                 struct rc_class c;
268                 /* The assumption here is that if an instruction has type
269                  * RC_INSTRUCTION_NORMAL then it is a TEX instruction.
270                  * r300 and r400 can't swizzle the result of a TEX lookup. */
271                 if (variable->Inst->Type == RC_INSTRUCTION_NORMAL) {
272                         writemask = RC_MASK_XYZW;
273                 }
274
275                 /* Check if it is possible to do swizzle packing for r300/r400
276                  * without creating non-native swizzles. */
277                 class_index = find_class(classes, writemask, 3);
278                 if (class_index < 0) {
279                         goto error;
280                 }
281                 c = classes[class_index];
282                 for (i = 0; i < c.WritemaskCount; i++) {
283                         int j;
284                         unsigned int conversion_swizzle =
285                                                 rc_make_conversion_swizzle(
286                                                 writemask, c.Writemasks[i]);
287                         for (j = 0; j < variable->ReaderCount; j++) {
288                                 unsigned int old_swizzle;
289                                 unsigned int new_swizzle;
290                                 struct rc_reader r = variable->Readers[j];
291                                 if (r.Inst->Type == RC_INSTRUCTION_PAIR ) {
292                                         old_swizzle = r.U.P.Arg->Swizzle;
293                                 } else {
294                                         old_swizzle = r.U.I.Src->Swizzle;
295                                 }
296                                 new_swizzle = rc_adjust_channels(
297                                         old_swizzle, conversion_swizzle);
298                                 if (!r300_swizzle_is_native_basic(new_swizzle)) {
299                                         can_change_writemask = 0;
300                                         break;
301                                 }
302                         }
303                         if (!can_change_writemask) {
304                                 break;
305                         }
306                 }
307         }
308
309         if (variable->Inst->Type == RC_INSTRUCTION_PAIR) {
310                 /* DDX/DDY seem to always fail when their writemasks are
311                  * changed.*/
312                 if (is_derivative(variable->Inst->U.P.RGB.Opcode)
313                     || is_derivative(variable->Inst->U.P.Alpha.Opcode)) {
314                         can_change_writemask = 0;
315                 }
316         }
317         for ( ; readers; readers = readers->Next) {
318                 struct rc_reader * r = readers->Item;
319                 if (r->Inst->Type == RC_INSTRUCTION_PAIR) {
320                         if (r->U.P.Arg->Source == RC_PAIR_PRESUB_SRC) {
321                                 can_change_writemask = 0;
322                                 break;
323                         }
324                         /* DDX/DDY also fail when their swizzles are changed. */
325                         if (is_derivative(r->Inst->U.P.RGB.Opcode)
326                             || is_derivative(r->Inst->U.P.Alpha.Opcode)) {
327                                 can_change_writemask = 0;
328                                 break;
329                         }
330                 }
331         }
332
333         class_index = find_class(classes, writemask,
334                                                 can_change_writemask ? 3 : 1);
335         if (class_index > -1) {
336                 return classes[class_index].Class;
337         } else {
338 error:
339                 rc_error(variable->C,
340                                 "Could not find class for index=%u mask=%u\n",
341                                 variable->Dst.Index, writemask);
342                 return 0;
343         }
344 }
345
346 static unsigned int overlap_live_intervals_array(
347         struct live_intervals * a,
348         struct live_intervals * b)
349 {
350         unsigned int a_chan, b_chan;
351         for (a_chan = 0; a_chan < 4; a_chan++) {
352                 for (b_chan = 0; b_chan < 4; b_chan++) {
353                         if (overlap_live_intervals(&a[a_chan], &b[b_chan])) {
354                                         return 1;
355                         }
356                 }
357         }
358         return 0;
359 }
360
361 static unsigned int reg_get_index(int reg)
362 {
363         return reg / RC_MASK_XYZW;
364 }
365
366 static unsigned int reg_get_writemask(int reg)
367 {
368         return (reg % RC_MASK_XYZW) + 1;
369 }
370
371 static int get_reg_id(unsigned int index, unsigned int writemask)
372 {
373         assert(writemask);
374         if (writemask == 0) {
375                 return 0;
376         }
377         return (index * RC_MASK_XYZW) + (writemask - 1);
378 }
379
380 #if VERBOSE
381 static void print_reg(int reg)
382 {
383         unsigned int index = reg_get_index(reg);
384         unsigned int mask = reg_get_writemask(reg);
385         fprintf(stderr, "Temp[%u].%c%c%c%c", index,
386                 mask & RC_MASK_X ? 'x' : '_',
387                 mask & RC_MASK_Y ? 'y' : '_',
388                 mask & RC_MASK_Z ? 'z' : '_',
389                 mask & RC_MASK_W ? 'w' : '_');
390 }
391 #endif
392
393 static void add_register_conflicts(
394         struct ra_regs * regs,
395         unsigned int max_temp_regs)
396 {
397         unsigned int index, a_mask, b_mask;
398         for (index = 0; index < max_temp_regs; index++) {
399                 for(a_mask = 1; a_mask <= RC_MASK_XYZW; a_mask++) {
400                         for (b_mask = a_mask + 1; b_mask <= RC_MASK_XYZW;
401                                                                 b_mask++) {
402                                 if (a_mask & b_mask) {
403                                         ra_add_reg_conflict(regs,
404                                                 get_reg_id(index, a_mask),
405                                                 get_reg_id(index, b_mask));
406                                 }
407                         }
408                 }
409         }
410 }
411
412 static void do_advanced_regalloc(struct regalloc_state * s)
413 {
414         struct rc_class rc_class_list [] = {
415                 {RC_REG_CLASS_SINGLE, 3, 0, 0,
416                         {RC_MASK_X,
417                          RC_MASK_Y,
418                          RC_MASK_Z}},
419                 {RC_REG_CLASS_DOUBLE, 3, 0, 0,
420                         {RC_MASK_X | RC_MASK_Y,
421                          RC_MASK_X | RC_MASK_Z,
422                          RC_MASK_Y | RC_MASK_Z}},
423                 {RC_REG_CLASS_TRIPLE, 1, 0, 0,
424                         {RC_MASK_X | RC_MASK_Y | RC_MASK_Z,
425                          RC_MASK_NONE,
426                          RC_MASK_NONE}},
427                 {RC_REG_CLASS_ALPHA, 1, 0, 0,
428                         {RC_MASK_W,
429                          RC_MASK_NONE,
430                          RC_MASK_NONE}},
431                 {RC_REG_CLASS_SINGLE_PLUS_ALPHA, 3, 0, 0,
432                         {RC_MASK_X | RC_MASK_W,
433                          RC_MASK_Y | RC_MASK_W,
434                          RC_MASK_Z | RC_MASK_W}},
435                 {RC_REG_CLASS_DOUBLE_PLUS_ALPHA, 3, 0, 0,
436                         {RC_MASK_X | RC_MASK_Y | RC_MASK_W,
437                          RC_MASK_X | RC_MASK_Z | RC_MASK_W,
438                          RC_MASK_Y | RC_MASK_Z | RC_MASK_W}},
439                 {RC_REG_CLASS_TRIPLE_PLUS_ALPHA, 1, 0, 0,
440                         {RC_MASK_X | RC_MASK_Y | RC_MASK_Z | RC_MASK_W,
441                         RC_MASK_NONE,
442                         RC_MASK_NONE}},
443                 {RC_REG_CLASS_X, 1, 0, 0,
444                         {RC_MASK_X,
445                         RC_MASK_NONE,
446                         RC_MASK_NONE}},
447                 {RC_REG_CLASS_Y, 1, 0, 0,
448                         {RC_MASK_Y,
449                         RC_MASK_NONE,
450                         RC_MASK_NONE}},
451                 {RC_REG_CLASS_Z, 1, 0, 0,
452                         {RC_MASK_Z,
453                         RC_MASK_NONE,
454                         RC_MASK_NONE}},
455                 {RC_REG_CLASS_XY, 1, 0, 0,
456                         {RC_MASK_X | RC_MASK_Y,
457                         RC_MASK_NONE,
458                         RC_MASK_NONE}},
459                 {RC_REG_CLASS_YZ, 1, 0, 0,
460                         {RC_MASK_Y | RC_MASK_Z,
461                         RC_MASK_NONE,
462                         RC_MASK_NONE}},
463                 {RC_REG_CLASS_XZ, 1, 0, 0,
464                         {RC_MASK_X | RC_MASK_Z,
465                         RC_MASK_NONE,
466                         RC_MASK_NONE}},
467                 {RC_REG_CLASS_XW, 1, 0, 0,
468                         {RC_MASK_X | RC_MASK_W,
469                         RC_MASK_NONE,
470                         RC_MASK_NONE}},
471                 {RC_REG_CLASS_YW, 1, 0, 0,
472                         {RC_MASK_Y | RC_MASK_W,
473                         RC_MASK_NONE,
474                         RC_MASK_NONE}},
475                 {RC_REG_CLASS_ZW, 1, 0, 0,
476                         {RC_MASK_Z | RC_MASK_W,
477                         RC_MASK_NONE,
478                         RC_MASK_NONE}},
479                 {RC_REG_CLASS_XYW, 1, 0, 0,
480                         {RC_MASK_X | RC_MASK_Y | RC_MASK_W,
481                         RC_MASK_NONE,
482                         RC_MASK_NONE}},
483                 {RC_REG_CLASS_YZW, 1, 0, 0,
484                         {RC_MASK_Y | RC_MASK_Z | RC_MASK_W,
485                         RC_MASK_NONE,
486                         RC_MASK_NONE}},
487                 {RC_REG_CLASS_XZW, 1, 0, 0,
488                         {RC_MASK_X | RC_MASK_Z | RC_MASK_W,
489                         RC_MASK_NONE,
490                         RC_MASK_NONE}}
491         };
492
493         unsigned int i, j, index, input_node, node_count, node_index;
494         unsigned int * node_classes;
495         unsigned int * input_classes;
496         struct rc_instruction * inst;
497         struct rc_list * var_ptr;
498         struct rc_list * variables;
499         struct ra_regs * regs;
500         struct ra_graph * graph;
501
502         /* Allocate the main ra data structure */
503         regs = ra_alloc_reg_set(s->C->max_temp_regs * RC_MASK_XYZW);
504
505         /* Get list of program variables */
506         variables = rc_get_variables(s->C);
507         node_count = rc_list_count(variables);
508         node_classes = memory_pool_malloc(&s->C->Pool,
509                         node_count * sizeof(unsigned int));
510         input_classes = memory_pool_malloc(&s->C->Pool,
511                         s->NumInputs * sizeof(unsigned int));
512
513         for (var_ptr = variables, node_index = 0; var_ptr;
514                                         var_ptr = var_ptr->Next, node_index++) {
515                 unsigned int class_index;
516                 /* Compute the live intervals */
517                 rc_variable_compute_live_intervals(var_ptr->Item);
518
519                 class_index = variable_get_class(var_ptr->Item, rc_class_list);
520
521                 /* If we haven't used this register class yet, mark it
522                  * as used and allocate space for it. */
523                 if (!rc_class_list[class_index].Used) {
524                         rc_class_list[class_index].Used = 1;
525                         rc_class_list[class_index].Id = ra_alloc_reg_class(regs);
526                 }
527
528                 node_classes[node_index] = rc_class_list[class_index].Id;
529         }
530
531
532         /* Assign registers to the classes */
533         for (i = 0; i < RC_REG_CLASS_COUNT; i++) {
534                 struct rc_class class = rc_class_list[i];
535                 if (!class.Used) {
536                         continue;
537                 }
538
539                 for (index = 0; index < s->C->max_temp_regs; index++) {
540                         for (j = 0; j < class.WritemaskCount; j++) {
541                                 int reg_id = get_reg_id(index,
542                                                         class.Writemasks[j]);
543                                 ra_class_add_reg(regs, class.Id, reg_id);
544                         }
545                 }
546         }
547
548         /* Add register conflicts */
549         add_register_conflicts(regs, s->C->max_temp_regs);
550
551         /* Calculate live intervals for input registers */
552         for (inst = s->C->Program.Instructions.Next;
553                                         inst != &s->C->Program.Instructions;
554                                         inst = inst->Next) {
555                 rc_opcode op = rc_get_flow_control_inst(inst);
556                 if (op == RC_OPCODE_BGNLOOP) {
557                         struct rc_instruction * endloop =
558                                                         rc_match_bgnloop(inst);
559                         if (endloop->IP > s->LoopEnd) {
560                                 s->LoopEnd = endloop->IP;
561                         }
562                 }
563                 rc_for_all_reads_mask(inst, scan_read_callback, s);
564         }
565
566         /* Create classes for input registers */
567         for (i = 0; i < s->NumInputs; i++) {
568                 unsigned int chan, class_id, writemask = 0;
569                 for (chan = 0; chan < 4; chan++) {
570                         if (s->Input[i].Live[chan].Used) {
571                                 writemask |= (1 << chan);
572                         }
573                 }
574                 s->Input[i].Writemask = writemask;
575                 if (!writemask) {
576                         continue;
577                 }
578
579                 class_id = ra_alloc_reg_class(regs);
580                 input_classes[i] = class_id;
581                 ra_class_add_reg(regs, class_id,
582                                 get_reg_id(s->Input[i].Index, writemask));
583         }
584
585         ra_set_finalize(regs);
586
587         graph = ra_alloc_interference_graph(regs, node_count + s->NumInputs);
588
589         /* Build the interference graph */
590         for (var_ptr = variables, node_index = 0; var_ptr;
591                                         var_ptr = var_ptr->Next,node_index++) {
592                 struct rc_list * a, * b;
593                 unsigned int b_index;
594
595                 ra_set_node_class(graph, node_index, node_classes[node_index]);
596
597                 for (a = var_ptr, b = var_ptr->Next, b_index = node_index + 1;
598                                                 b; b = b->Next, b_index++) {
599                         struct rc_variable * var_a = a->Item;
600                         while (var_a) {
601                                 struct rc_variable * var_b = b->Item;
602                                 while (var_b) {
603                                         if (overlap_live_intervals_array(var_a->Live, var_b->Live)) {
604                                                 ra_add_node_interference(graph,
605                                                         node_index, b_index);
606                                         }
607                                         var_b = var_b->Friend;
608                                 }
609                                 var_a = var_a->Friend;
610                         }
611                 }
612         }
613
614         /* Add input registers to the interference graph */
615         for (i = 0, input_node = 0; i< s->NumInputs; i++) {
616                 if (!s->Input[i].Writemask) {
617                         continue;
618                 }
619                 ra_set_node_class(graph, node_count + input_node,
620                                                         input_classes[i]);
621                 for (var_ptr = variables, node_index = 0;
622                                 var_ptr; var_ptr = var_ptr->Next, node_index++) {
623                         struct rc_variable * var = var_ptr->Item;
624                         if (overlap_live_intervals_array(s->Input[i].Live,
625                                                                 var->Live)) {
626                                 ra_add_node_interference(graph, node_index,
627                                                 node_count + input_node);
628                         }
629                 }
630                 /* Manually allocate a register for this input */
631                 ra_set_node_reg(graph, node_count + input_node, get_reg_id(
632                                 s->Input[i].Index, s->Input[i].Writemask));
633                 input_node++;
634         }
635
636         if (!ra_allocate_no_spills(graph)) {
637                 rc_error(s->C, "Ran out of hardware temporaries\n");
638                 return;
639         }
640
641         /* Rewrite the registers */
642         for (var_ptr = variables, node_index = 0; var_ptr;
643                                 var_ptr = var_ptr->Next, node_index++) {
644                 int reg = ra_get_node_reg(graph, node_index);
645                 unsigned int writemask = reg_get_writemask(reg);
646                 unsigned int index = reg_get_index(reg);
647                 struct rc_variable * var = var_ptr->Item;
648
649                 if (!s->C->is_r500 && var->Inst->Type == RC_INSTRUCTION_NORMAL) {
650                         writemask = rc_variable_writemask_sum(var);
651                 }
652
653                 if (var->Dst.File == RC_FILE_INPUT) {
654                         continue;
655                 }
656                 rc_variable_change_dst(var, index, writemask);
657         }
658
659         ralloc_free(graph);
660         ralloc_free(regs);
661 }
662
663 /**
664  * @param user This parameter should be a pointer to an integer value.  If this
665  * integer value is zero, then a simple register allocator will be used that
666  * only allocates space for input registers (\sa do_regalloc_inputs_only).  If
667  * user is non-zero, then the regular register allocator will be used
668  * (\sa do_regalloc).
669   */
670 void rc_pair_regalloc(struct radeon_compiler *cc, void *user)
671 {
672         struct r300_fragment_program_compiler *c =
673                                 (struct r300_fragment_program_compiler*)cc;
674         struct regalloc_state s;
675         int * do_full_regalloc = (int*)user;
676
677         memset(&s, 0, sizeof(s));
678         s.C = cc;
679         s.NumInputs = rc_get_max_index(cc, RC_FILE_INPUT) + 1;
680         s.Input = memory_pool_malloc(&cc->Pool,
681                         s.NumInputs * sizeof(struct register_info));
682         memset(s.Input, 0, s.NumInputs * sizeof(struct register_info));
683
684         s.NumTemporaries = rc_get_max_index(cc, RC_FILE_TEMPORARY) + 1;
685         s.Temporary = memory_pool_malloc(&cc->Pool,
686                         s.NumTemporaries * sizeof(struct register_info));
687         memset(s.Temporary, 0, s.NumTemporaries * sizeof(struct register_info));
688
689         rc_recompute_ips(s.C);
690
691         c->AllocateHwInputs(c, &alloc_input_simple, &s);
692         if (*do_full_regalloc) {
693                 do_advanced_regalloc(&s);
694         } else {
695                 s.Simple = 1;
696                 do_regalloc_inputs_only(&s);
697         }
698
699         /* Rewrite inputs and if we are doing the simple allocation, rewrite
700          * temporaries too. */
701         for (struct rc_instruction *inst = s.C->Program.Instructions.Next;
702                                         inst != &s.C->Program.Instructions;
703                                         inst = inst->Next) {
704                 rc_remap_registers(inst, &remap_register, &s);
705         }
706 }