2
* Mesa 3-D graphics library
5
* Copyright (C) 2009 VMware, Inc. All Rights Reserved.
7
* Permission is hereby granted, free of charge, to any person obtaining a
8
* copy of this software and associated documentation files (the "Software"),
9
* to deal in the Software without restriction, including without limitation
10
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
* and/or sell copies of the Software, and to permit persons to whom the
12
* Software is furnished to do so, subject to the following conditions:
14
* The above copyright notice and this permission notice shall be included
15
* in all copies or substantial portions of the Software.
17
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20
* VMWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
#include "main/glheader.h"
28
#include "main/context.h"
29
#include "main/macros.h"
31
#include "prog_instruction.h"
32
#include "prog_optimize.h"
33
#include "prog_print.h"
36
#define MAX_LOOP_NESTING 50
39
static GLboolean dbg = GL_FALSE;
41
/* Returns the mask of channels read from the given srcreg in this instruction.
44
get_src_arg_mask(const struct prog_instruction *inst, int arg)
46
int writemask = inst->DstReg.WriteMask;
49
writemask = WRITEMASK_XYZW;
51
switch (inst->Opcode) {
71
return WRITEMASK_XYZW;
76
* In 'prog' remove instruction[i] if removeFlags[i] == TRUE.
77
* \return number of instructions removed
80
remove_instructions(struct gl_program *prog, const GLboolean *removeFlags)
82
GLint i, removeEnd = 0, removeCount = 0;
83
GLuint totalRemoved = 0;
86
for (i = prog->NumInstructions - 1; i >= 0; i--) {
89
if (removeCount == 0) {
90
/* begin a run of instructions to remove */
95
/* extend the run of instructions to remove */
100
/* don't remove this instruction, but check if the preceeding
101
* instructions are to be removed.
103
if (removeCount > 0) {
104
GLint removeStart = removeEnd - removeCount + 1;
105
_mesa_delete_instructions(prog, removeStart, removeCount);
106
removeStart = removeCount = 0; /* reset removal info */
110
/* Finish removing if the first instruction was to be removed. */
111
if (removeCount > 0) {
112
GLint removeStart = removeEnd - removeCount + 1;
113
_mesa_delete_instructions(prog, removeStart, removeCount);
120
* Remap register indexes according to map.
121
* \param prog the program to search/replace
122
* \param file the type of register file to search/replace
123
* \param map maps old register indexes to new indexes
126
replace_regs(struct gl_program *prog, gl_register_file file, const GLint map[])
130
for (i = 0; i < prog->NumInstructions; i++) {
131
struct prog_instruction *inst = prog->Instructions + i;
132
const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
134
for (j = 0; j < numSrc; j++) {
135
if (inst->SrcReg[j].File == file) {
136
GLuint index = inst->SrcReg[j].Index;
137
ASSERT(map[index] >= 0);
138
inst->SrcReg[j].Index = map[index];
141
if (inst->DstReg.File == file) {
142
const GLuint index = inst->DstReg.Index;
143
ASSERT(map[index] >= 0);
144
inst->DstReg.Index = map[index];
151
* Consolidate temporary registers to use low numbers. For example, if the
152
* shader only uses temps 4, 5, 8, replace them with 0, 1, 2.
155
_mesa_consolidate_registers(struct gl_program *prog)
157
GLboolean tempUsed[MAX_PROGRAM_TEMPS];
158
GLint tempMap[MAX_PROGRAM_TEMPS];
159
GLuint tempMax = 0, i;
162
printf("Optimize: Begin register consolidation\n");
165
memset(tempUsed, 0, sizeof(tempUsed));
167
for (i = 0; i < MAX_PROGRAM_TEMPS; i++) {
171
/* set tempUsed[i] if temporary [i] is referenced */
172
for (i = 0; i < prog->NumInstructions; i++) {
173
const struct prog_instruction *inst = prog->Instructions + i;
174
const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
176
for (j = 0; j < numSrc; j++) {
177
if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) {
178
const GLuint index = inst->SrcReg[j].Index;
179
ASSERT(index < MAX_PROGRAM_TEMPS);
180
tempUsed[index] = GL_TRUE;
181
tempMax = MAX2(tempMax, index);
185
if (inst->DstReg.File == PROGRAM_TEMPORARY) {
186
const GLuint index = inst->DstReg.Index;
187
ASSERT(index < MAX_PROGRAM_TEMPS);
188
tempUsed[index] = GL_TRUE;
189
tempMax = MAX2(tempMax, index);
193
/* allocate a new index for each temp that's used */
196
for (i = 0; i <= tempMax; i++) {
198
tempMap[i] = freeTemp++;
199
/*printf("replace %u with %u\n", i, tempMap[i]);*/
202
if (freeTemp == tempMax + 1) {
203
/* no consolidation possible */
207
printf("Replace regs 0..%u with 0..%u\n", tempMax, freeTemp-1);
211
replace_regs(prog, PROGRAM_TEMPORARY, tempMap);
214
printf("Optimize: End register consolidation\n");
220
* Remove dead instructions from the given program.
221
* This is very primitive for now. Basically look for temp registers
222
* that are written to but never read. Remove any instructions that
223
* write to such registers. Be careful with condition code setters.
226
_mesa_remove_dead_code(struct gl_program *prog)
228
GLboolean tempRead[MAX_PROGRAM_TEMPS][4];
229
GLboolean *removeInst; /* per-instruction removal flag */
230
GLuint i, rem = 0, comp;
232
memset(tempRead, 0, sizeof(tempRead));
235
printf("Optimize: Begin dead code removal\n");
236
/*_mesa_print_program(prog);*/
239
removeInst = (GLboolean *)
240
calloc(1, prog->NumInstructions * sizeof(GLboolean));
242
/* Determine which temps are read and written */
243
for (i = 0; i < prog->NumInstructions; i++) {
244
const struct prog_instruction *inst = prog->Instructions + i;
245
const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
249
for (j = 0; j < numSrc; j++) {
250
if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) {
251
const GLuint index = inst->SrcReg[j].Index;
253
ASSERT(index < MAX_PROGRAM_TEMPS);
254
read_mask = get_src_arg_mask(inst, j);
256
if (inst->SrcReg[j].RelAddr) {
258
printf("abort remove dead code (indirect temp)\n");
262
for (comp = 0; comp < 4; comp++) {
263
GLuint swz = (inst->SrcReg[j].Swizzle >> (3 * comp)) & 0x7;
265
if ((read_mask & (1 << comp)) == 0)
270
tempRead[index][0] = GL_TRUE;
273
tempRead[index][1] = GL_TRUE;
276
tempRead[index][2] = GL_TRUE;
279
tempRead[index][3] = GL_TRUE;
287
if (inst->DstReg.File == PROGRAM_TEMPORARY) {
288
const GLuint index = inst->DstReg.Index;
289
ASSERT(index < MAX_PROGRAM_TEMPS);
291
if (inst->DstReg.RelAddr) {
293
printf("abort remove dead code (indirect temp)\n");
297
if (inst->CondUpdate) {
298
/* If we're writing to this register and setting condition
299
* codes we cannot remove the instruction. Prevent removal
300
* by setting the 'read' flag.
302
tempRead[index][0] = GL_TRUE;
303
tempRead[index][1] = GL_TRUE;
304
tempRead[index][2] = GL_TRUE;
305
tempRead[index][3] = GL_TRUE;
310
/* find instructions that write to dead registers, flag for removal */
311
for (i = 0; i < prog->NumInstructions; i++) {
312
struct prog_instruction *inst = prog->Instructions + i;
313
const GLuint numDst = _mesa_num_inst_dst_regs(inst->Opcode);
315
if (numDst != 0 && inst->DstReg.File == PROGRAM_TEMPORARY) {
316
GLint chan, index = inst->DstReg.Index;
318
for (chan = 0; chan < 4; chan++) {
319
if (!tempRead[index][chan] &&
320
inst->DstReg.WriteMask & (1 << chan)) {
322
printf("Remove writemask on %u.%c\n", i,
323
chan == 3 ? 'w' : 'x' + chan);
325
inst->DstReg.WriteMask &= ~(1 << chan);
330
if (inst->DstReg.WriteMask == 0) {
331
/* If we cleared all writes, the instruction can be removed. */
333
printf("Remove instruction %u: \n", i);
334
removeInst[i] = GL_TRUE;
339
/* now remove the instructions which aren't needed */
340
rem = remove_instructions(prog, removeInst);
343
printf("Optimize: End dead code removal.\n");
344
printf(" %u channel writes removed\n", rem);
345
printf(" %u instructions removed\n", rem);
346
/*_mesa_print_program(prog);*/
363
* Scan forward in program from 'start' for the next occurance of TEMP[index].
364
* Return READ, WRITE, FLOW or END to indicate the next usage or an indicator
365
* that we can't look further.
368
find_next_temp_use(const struct gl_program *prog, GLuint start, GLuint index)
372
for (i = start; i < prog->NumInstructions; i++) {
373
const struct prog_instruction *inst = prog->Instructions + i;
374
switch (inst->Opcode) {
382
const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
384
for (j = 0; j < numSrc; j++) {
385
if (inst->SrcReg[j].File == PROGRAM_TEMPORARY &&
386
inst->SrcReg[j].Index == index)
389
if (inst->DstReg.File == PROGRAM_TEMPORARY &&
390
inst->DstReg.Index == index)
399
static GLboolean _mesa_is_flow_control_opcode(enum prog_opcode opcode)
421
* Try to remove use of extraneous MOV instructions, to free them up for dead
425
_mesa_remove_extra_move_use(struct gl_program *prog)
430
printf("Optimize: Begin remove extra move use\n");
431
_mesa_print_program(prog);
435
* Look for sequences such as this:
438
* FOO tmpY, tmpX, arg1;
442
* FOO tmpY, arg0, arg1;
445
for (i = 0; i + 1 < prog->NumInstructions; i++) {
446
const struct prog_instruction *mov = prog->Instructions + i;
448
if (mov->Opcode != OPCODE_MOV ||
449
mov->DstReg.File != PROGRAM_TEMPORARY ||
450
mov->DstReg.RelAddr ||
451
mov->DstReg.CondMask != COND_TR ||
452
mov->SaturateMode != SATURATE_OFF ||
453
mov->SrcReg[0].RelAddr)
456
/* Walk through remaining instructions until the or src reg gets
457
* rewritten or we get into some flow-control, eliminating the use of
460
for (j = i + 1; j < prog->NumInstructions; j++) {
461
struct prog_instruction *inst2 = prog->Instructions + j;
464
if (_mesa_is_flow_control_opcode(inst2->Opcode))
467
/* First rewrite this instruction's args if appropriate. */
468
for (arg = 0; arg < _mesa_num_inst_src_regs(inst2->Opcode); arg++) {
470
int read_mask = get_src_arg_mask(inst2, arg);
472
if (inst2->SrcReg[arg].File != mov->DstReg.File ||
473
inst2->SrcReg[arg].Index != mov->DstReg.Index ||
474
inst2->SrcReg[arg].RelAddr ||
475
inst2->SrcReg[arg].Abs)
478
/* Check that all the sources for this arg of inst2 come from inst1
481
for (comp = 0; comp < 4; comp++) {
482
int src_swz = GET_SWZ(inst2->SrcReg[arg].Swizzle, comp);
484
/* If the MOV didn't write that channel, can't use it. */
485
if ((read_mask & (1 << comp)) &&
486
src_swz <= SWIZZLE_W &&
487
(mov->DstReg.WriteMask & (1 << src_swz)) == 0)
493
/* Adjust the swizzles of inst2 to point at MOV's source */
494
for (comp = 0; comp < 4; comp++) {
495
int inst2_swz = GET_SWZ(inst2->SrcReg[arg].Swizzle, comp);
497
if (inst2_swz <= SWIZZLE_W) {
498
GLuint s = GET_SWZ(mov->SrcReg[0].Swizzle, inst2_swz);
499
inst2->SrcReg[arg].Swizzle &= ~(7 << (3 * comp));
500
inst2->SrcReg[arg].Swizzle |= s << (3 * comp);
501
inst2->SrcReg[arg].Negate ^= (((mov->SrcReg[0].Negate >>
502
inst2_swz) & 0x1) << comp);
505
inst2->SrcReg[arg].File = mov->SrcReg[0].File;
506
inst2->SrcReg[arg].Index = mov->SrcReg[0].Index;
509
/* If this instruction overwrote part of the move, our time is up. */
510
if ((inst2->DstReg.File == mov->DstReg.File &&
511
(inst2->DstReg.RelAddr ||
512
inst2->DstReg.Index == mov->DstReg.Index)) ||
513
(inst2->DstReg.File == mov->SrcReg[0].File &&
514
(inst2->DstReg.RelAddr ||
515
inst2->DstReg.Index == mov->SrcReg[0].Index)))
521
printf("Optimize: End remove extra move use.\n");
522
/*_mesa_print_program(prog);*/
527
* Try to remove extraneous MOV instructions from the given program.
530
_mesa_remove_extra_moves(struct gl_program *prog)
532
GLboolean *removeInst; /* per-instruction removal flag */
533
GLuint i, rem, loopNesting = 0, subroutineNesting = 0;
536
printf("Optimize: Begin remove extra moves\n");
537
_mesa_print_program(prog);
540
removeInst = (GLboolean *)
541
calloc(1, prog->NumInstructions * sizeof(GLboolean));
544
* Look for sequences such as this:
545
* FOO tmpX, arg0, arg1;
548
* FOO tmpY, arg0, arg1;
551
for (i = 0; i < prog->NumInstructions; i++) {
552
const struct prog_instruction *inst = prog->Instructions + i;
554
switch (inst->Opcode) {
570
subroutineNesting == 0 &&
571
inst->SrcReg[0].File == PROGRAM_TEMPORARY &&
572
inst->SrcReg[0].Swizzle == SWIZZLE_XYZW) {
573
/* see if this MOV can be removed */
574
const GLuint tempIndex = inst->SrcReg[0].Index;
575
struct prog_instruction *prevInst;
578
/* get pointer to previous instruction */
580
while (prevI > 0 && removeInst[prevI])
582
prevInst = prog->Instructions + prevI;
584
if (prevInst->DstReg.File == PROGRAM_TEMPORARY &&
585
prevInst->DstReg.Index == tempIndex &&
586
prevInst->DstReg.WriteMask == WRITEMASK_XYZW) {
588
enum temp_use next_use =
589
find_next_temp_use(prog, i + 1, tempIndex);
591
if (next_use == WRITE || next_use == END) {
592
/* OK, we can safely remove this MOV instruction.
594
* prevI: FOO tempIndex, x, y;
595
* i: MOV z, tempIndex;
597
* prevI: FOO z, x, y;
600
/* patch up prev inst */
601
prevInst->DstReg.File = inst->DstReg.File;
602
prevInst->DstReg.Index = inst->DstReg.Index;
604
/* flag this instruction for removal */
605
removeInst[i] = GL_TRUE;
608
printf("Remove MOV at %u\n", i);
609
printf("new prev inst %u: ", prevI);
610
_mesa_print_instruction(prevInst);
621
/* now remove the instructions which aren't needed */
622
rem = remove_instructions(prog, removeInst);
627
printf("Optimize: End remove extra moves. %u instructions removed\n", rem);
628
/*_mesa_print_program(prog);*/
633
/** A live register interval */
636
GLuint Reg; /** The temporary register index */
637
GLuint Start, End; /** Start/end instruction numbers */
641
/** A list of register intervals */
645
struct interval Intervals[MAX_PROGRAM_TEMPS];
650
append_interval(struct interval_list *list, const struct interval *inv)
652
list->Intervals[list->Num++] = *inv;
656
/** Insert interval inv into list, sorted by interval end */
658
insert_interval_by_end(struct interval_list *list, const struct interval *inv)
660
/* XXX we could do a binary search insertion here since list is sorted */
661
GLint i = list->Num - 1;
662
while (i >= 0 && list->Intervals[i].End > inv->End) {
663
list->Intervals[i + 1] = list->Intervals[i];
666
list->Intervals[i + 1] = *inv;
672
for (i = 0; i + 1 < list->Num; i++) {
673
ASSERT(list->Intervals[i].End <= list->Intervals[i + 1].End);
680
/** Remove the given interval from the interval list */
682
remove_interval(struct interval_list *list, const struct interval *inv)
684
/* XXX we could binary search since list is sorted */
686
for (k = 0; k < list->Num; k++) {
687
if (list->Intervals[k].Reg == inv->Reg) {
688
/* found, remove it */
689
ASSERT(list->Intervals[k].Start == inv->Start);
690
ASSERT(list->Intervals[k].End == inv->End);
691
while (k < list->Num - 1) {
692
list->Intervals[k] = list->Intervals[k + 1];
702
/** called by qsort() */
704
compare_start(const void *a, const void *b)
706
const struct interval *ia = (const struct interval *) a;
707
const struct interval *ib = (const struct interval *) b;
708
if (ia->Start < ib->Start)
710
else if (ia->Start > ib->Start)
716
/** sort the interval list according to interval starts */
718
sort_interval_list_by_start(struct interval_list *list)
720
qsort(list->Intervals, list->Num, sizeof(struct interval), compare_start);
724
for (i = 0; i + 1 < list->Num; i++) {
725
ASSERT(list->Intervals[i].Start <= list->Intervals[i + 1].Start);
733
* Update the intermediate interval info for register 'index' and
737
update_interval(GLint intBegin[], GLint intEnd[], GLuint index, GLuint ic)
739
ASSERT(index < MAX_PROGRAM_TEMPS);
740
if (intBegin[index] == -1) {
741
ASSERT(intEnd[index] == -1);
742
intBegin[index] = intEnd[index] = ic;
751
* Find first/last instruction that references each temporary register.
754
_mesa_find_temp_intervals(const struct prog_instruction *instructions,
755
GLuint numInstructions,
756
GLint intBegin[MAX_PROGRAM_TEMPS],
757
GLint intEnd[MAX_PROGRAM_TEMPS])
761
GLuint Start, End; /**< Start, end instructions of loop */
763
struct loop_info loopStack[MAX_LOOP_NESTING];
764
GLuint loopStackDepth = 0;
767
for (i = 0; i < MAX_PROGRAM_TEMPS; i++){
768
intBegin[i] = intEnd[i] = -1;
771
/* Scan instructions looking for temporary registers */
772
for (i = 0; i < numInstructions; i++) {
773
const struct prog_instruction *inst = instructions + i;
774
if (inst->Opcode == OPCODE_BGNLOOP) {
775
loopStack[loopStackDepth].Start = i;
776
loopStack[loopStackDepth].End = inst->BranchTarget;
779
else if (inst->Opcode == OPCODE_ENDLOOP) {
782
else if (inst->Opcode == OPCODE_CAL) {
786
const GLuint numSrc = 3;/*_mesa_num_inst_src_regs(inst->Opcode);*/
788
for (j = 0; j < numSrc; j++) {
789
if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) {
790
const GLuint index = inst->SrcReg[j].Index;
791
if (inst->SrcReg[j].RelAddr)
793
update_interval(intBegin, intEnd, index, i);
794
if (loopStackDepth > 0) {
795
/* extend temp register's interval to end of loop */
796
GLuint loopEnd = loopStack[loopStackDepth - 1].End;
797
update_interval(intBegin, intEnd, index, loopEnd);
801
if (inst->DstReg.File == PROGRAM_TEMPORARY) {
802
const GLuint index = inst->DstReg.Index;
803
if (inst->DstReg.RelAddr)
805
update_interval(intBegin, intEnd, index, i);
806
if (loopStackDepth > 0) {
807
/* extend temp register's interval to end of loop */
808
GLuint loopEnd = loopStack[loopStackDepth - 1].End;
809
update_interval(intBegin, intEnd, index, loopEnd);
820
* Find the live intervals for each temporary register in the program.
821
* For register R, the interval [A,B] indicates that R is referenced
822
* from instruction A through instruction B.
823
* Special consideration is needed for loops and subroutines.
824
* \return GL_TRUE if success, GL_FALSE if we cannot proceed for some reason
827
find_live_intervals(struct gl_program *prog,
828
struct interval_list *liveIntervals)
830
GLint intBegin[MAX_PROGRAM_TEMPS], intEnd[MAX_PROGRAM_TEMPS];
834
* Note: we'll return GL_FALSE below if we find relative indexing
835
* into the TEMP register file. We can't handle that yet.
836
* We also give up on subroutines for now.
840
printf("Optimize: Begin find intervals\n");
843
/* build intermediate arrays */
844
if (!_mesa_find_temp_intervals(prog->Instructions, prog->NumInstructions,
848
/* Build live intervals list from intermediate arrays */
849
liveIntervals->Num = 0;
850
for (i = 0; i < MAX_PROGRAM_TEMPS; i++) {
851
if (intBegin[i] >= 0) {
854
inv.Start = intBegin[i];
856
append_interval(liveIntervals, &inv);
860
/* Sort the list according to interval starts */
861
sort_interval_list_by_start(liveIntervals);
864
/* print interval info */
865
for (i = 0; i < liveIntervals->Num; i++) {
866
const struct interval *inv = liveIntervals->Intervals + i;
867
printf("Reg[%d] live [%d, %d]:",
868
inv->Reg, inv->Start, inv->End);
871
for (j = 0; j < inv->Start; j++)
873
for (j = inv->Start; j <= inv->End; j++)
884
/** Scan the array of used register flags to find free entry */
886
alloc_register(GLboolean usedRegs[MAX_PROGRAM_TEMPS])
889
for (k = 0; k < MAX_PROGRAM_TEMPS; k++) {
891
usedRegs[k] = GL_TRUE;
900
* This function implements "Linear Scan Register Allocation" to reduce
901
* the number of temporary registers used by the program.
903
* We compute the "live interval" for all temporary registers then
904
* examine the overlap of the intervals to allocate new registers.
905
* Basically, if two intervals do not overlap, they can use the same register.
908
_mesa_reallocate_registers(struct gl_program *prog)
910
struct interval_list liveIntervals;
911
GLint registerMap[MAX_PROGRAM_TEMPS];
912
GLboolean usedRegs[MAX_PROGRAM_TEMPS];
917
printf("Optimize: Begin live-interval register reallocation\n");
918
_mesa_print_program(prog);
921
for (i = 0; i < MAX_PROGRAM_TEMPS; i++){
923
usedRegs[i] = GL_FALSE;
926
if (!find_live_intervals(prog, &liveIntervals)) {
928
printf("Aborting register reallocation\n");
933
struct interval_list activeIntervals;
934
activeIntervals.Num = 0;
936
/* loop over live intervals, allocating a new register for each */
937
for (i = 0; i < liveIntervals.Num; i++) {
938
const struct interval *live = liveIntervals.Intervals + i;
941
printf("Consider register %u\n", live->Reg);
943
/* Expire old intervals. Intervals which have ended with respect
944
* to the live interval can have their remapped registers freed.
948
for (j = 0; j < (GLint) activeIntervals.Num; j++) {
949
const struct interval *inv = activeIntervals.Intervals + j;
950
if (inv->End >= live->Start) {
951
/* Stop now. Since the activeInterval list is sorted
952
* we know we don't have to go further.
957
/* Interval 'inv' has expired */
958
const GLint regNew = registerMap[inv->Reg];
962
printf(" expire interval for reg %u\n", inv->Reg);
964
/* remove interval j from active list */
965
remove_interval(&activeIntervals, inv);
966
j--; /* counter-act j++ in for-loop above */
968
/* return register regNew to the free pool */
970
printf(" free reg %d\n", regNew);
971
ASSERT(usedRegs[regNew] == GL_TRUE);
972
usedRegs[regNew] = GL_FALSE;
977
/* find a free register for this live interval */
979
const GLint k = alloc_register(usedRegs);
981
/* out of registers, give up */
984
registerMap[live->Reg] = k;
985
maxTemp = MAX2(maxTemp, k);
987
printf(" remap register %u -> %d\n", live->Reg, k);
990
/* Insert this live interval into the active list which is sorted
991
* by increasing end points.
993
insert_interval_by_end(&activeIntervals, live);
997
if (maxTemp + 1 < (GLint) liveIntervals.Num) {
998
/* OK, we've reduced the number of registers needed.
999
* Scan the program and replace all the old temporary register
1000
* indexes with the new indexes.
1002
replace_regs(prog, PROGRAM_TEMPORARY, registerMap);
1004
prog->NumTemporaries = maxTemp + 1;
1008
printf("Optimize: End live-interval register reallocation\n");
1009
printf("Num temp regs before: %u after: %u\n",
1010
liveIntervals.Num, maxTemp + 1);
1011
_mesa_print_program(prog);
1017
* Apply optimizations to the given program to eliminate unnecessary
1018
* instructions, temp regs, etc.
1021
_mesa_optimize_program(GLcontext *ctx, struct gl_program *program)
1023
_mesa_remove_extra_move_use(program);
1026
_mesa_remove_dead_code(program);
1028
if (0) /* not tested much yet */
1029
_mesa_remove_extra_moves(program);
1032
_mesa_consolidate_registers(program);
1034
_mesa_reallocate_registers(program);