OSDN Git Service

c1013a5a2af2c257fb3862451fe40aa6954bc87e
[android-x86/external-mesa.git] / src / mesa / program / prog_optimize.c
1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.5
4  *
5  * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
6  *
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:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
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.
23  */
24
25
26
27 #include "main/glheader.h"
28 #include "main/context.h"
29 #include "main/macros.h"
30 #include "program.h"
31 #include "prog_instruction.h"
32 #include "prog_optimize.h"
33 #include "prog_print.h"
34
35
36 #define MAX_LOOP_NESTING 50
37 /* MAX_PROGRAM_TEMPS is a low number (256), and we want to be able to
38  * register allocate many temporary values into that small number of
39  * temps.  So allow large temporary indices coming into the register
40  * allocator.
41  */
42 #define REG_ALLOCATE_MAX_PROGRAM_TEMPS  ((1 << INST_INDEX_BITS) - 1)
43
44 static GLboolean dbg = GL_FALSE;
45
46 #define NO_MASK 0xf
47
48 /**
49  * Returns the mask of channels (bitmask of WRITEMASK_X,Y,Z,W) which
50  * are read from the given src in this instruction, We also provide
51  * one optional masks which may mask other components in the dst
52  * register
53  */
54 static GLuint
55 get_src_arg_mask(const struct prog_instruction *inst,
56                  GLuint arg, GLuint dst_mask)
57 {
58    GLuint read_mask, channel_mask;
59    GLuint comp;
60
61    ASSERT(arg < _mesa_num_inst_src_regs(inst->Opcode));
62
63    /* Form the dst register, find the written channels */
64    if (inst->CondUpdate) {
65       channel_mask = WRITEMASK_XYZW;
66    }
67    else {
68       switch (inst->Opcode) {
69       case OPCODE_MOV:
70       case OPCODE_MIN:
71       case OPCODE_MAX:
72       case OPCODE_ABS:
73       case OPCODE_ADD:
74       case OPCODE_MAD:
75       case OPCODE_MUL:
76       case OPCODE_SUB:
77       case OPCODE_CMP:
78       case OPCODE_FLR:
79       case OPCODE_FRC:
80       case OPCODE_LRP:
81       case OPCODE_SEQ:
82       case OPCODE_SGE:
83       case OPCODE_SGT:
84       case OPCODE_SLE:
85       case OPCODE_SLT:
86       case OPCODE_SNE:
87       case OPCODE_SSG:
88          channel_mask = inst->DstReg.WriteMask & dst_mask;
89          break;
90       case OPCODE_RCP:
91       case OPCODE_SIN:
92       case OPCODE_COS:
93       case OPCODE_RSQ:
94       case OPCODE_POW:
95       case OPCODE_EX2:
96       case OPCODE_LOG:
97          channel_mask = WRITEMASK_X;
98          break;
99       case OPCODE_DP2:
100          channel_mask = WRITEMASK_XY;
101          break;
102       case OPCODE_DP3:
103       case OPCODE_XPD:
104          channel_mask = WRITEMASK_XYZ;
105          break;
106       default:
107          channel_mask = WRITEMASK_XYZW;
108          break;
109       }
110    }
111
112    /* Now, given the src swizzle and the written channels, find which
113     * components are actually read
114     */
115    read_mask = 0x0;
116    for (comp = 0; comp < 4; ++comp) {
117       const GLuint coord = GET_SWZ(inst->SrcReg[arg].Swizzle, comp);
118       ASSERT(coord < 4);
119       if (channel_mask & (1 << comp) && coord <= SWIZZLE_W)
120          read_mask |= 1 << coord;
121    }
122
123    return read_mask;
124 }
125
126
127 /**
128  * For a MOV instruction, compute a write mask when src register also has
129  * a mask
130  */
131 static GLuint
132 get_dst_mask_for_mov(const struct prog_instruction *mov, GLuint src_mask)
133 {
134    const GLuint mask = mov->DstReg.WriteMask;
135    GLuint comp;
136    GLuint updated_mask = 0x0;
137
138    ASSERT(mov->Opcode == OPCODE_MOV);
139
140    for (comp = 0; comp < 4; ++comp) {
141       GLuint src_comp;
142       if ((mask & (1 << comp)) == 0)
143          continue;
144       src_comp = GET_SWZ(mov->SrcReg[0].Swizzle, comp);
145       if ((src_mask & (1 << src_comp)) == 0)
146          continue;
147       updated_mask |= 1 << comp;
148    }
149
150    return updated_mask;
151 }
152
153
154 /**
155  * Ensure that the swizzle is regular.  That is, all of the swizzle
156  * terms are SWIZZLE_X,Y,Z,W and not SWIZZLE_ZERO or SWIZZLE_ONE.
157  */
158 static GLboolean
159 is_swizzle_regular(GLuint swz)
160 {
161    return GET_SWZ(swz,0) <= SWIZZLE_W &&
162           GET_SWZ(swz,1) <= SWIZZLE_W &&
163           GET_SWZ(swz,2) <= SWIZZLE_W &&
164           GET_SWZ(swz,3) <= SWIZZLE_W;
165 }
166
167
168 /**
169  * In 'prog' remove instruction[i] if removeFlags[i] == TRUE.
170  * \return number of instructions removed
171  */
172 static GLuint
173 remove_instructions(struct gl_program *prog, const GLboolean *removeFlags)
174 {
175    GLint i, removeEnd = 0, removeCount = 0;
176    GLuint totalRemoved = 0;
177
178    /* go backward */
179    for (i = prog->NumInstructions - 1; i >= 0; i--) {
180       if (removeFlags[i]) {
181          totalRemoved++;
182          if (removeCount == 0) {
183             /* begin a run of instructions to remove */
184             removeEnd = i;
185             removeCount = 1;
186          }
187          else {
188             /* extend the run of instructions to remove */
189             removeCount++;
190          }
191       }
192       else {
193          /* don't remove this instruction, but check if the preceeding
194           * instructions are to be removed.
195           */
196          if (removeCount > 0) {
197             GLint removeStart = removeEnd - removeCount + 1;
198             _mesa_delete_instructions(prog, removeStart, removeCount);
199             removeStart = removeCount = 0; /* reset removal info */
200          }
201       }
202    }
203    /* Finish removing if the first instruction was to be removed. */
204    if (removeCount > 0) {
205       GLint removeStart = removeEnd - removeCount + 1;
206       _mesa_delete_instructions(prog, removeStart, removeCount);
207    }
208    return totalRemoved;
209 }
210
211
212 /**
213  * Remap register indexes according to map.
214  * \param prog  the program to search/replace
215  * \param file  the type of register file to search/replace
216  * \param map  maps old register indexes to new indexes
217  */
218 static void
219 replace_regs(struct gl_program *prog, gl_register_file file, const GLint map[])
220 {
221    GLuint i;
222
223    for (i = 0; i < prog->NumInstructions; i++) {
224       struct prog_instruction *inst = prog->Instructions + i;
225       const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
226       GLuint j;
227       for (j = 0; j < numSrc; j++) {
228          if (inst->SrcReg[j].File == file) {
229             GLuint index = inst->SrcReg[j].Index;
230             ASSERT(map[index] >= 0);
231             inst->SrcReg[j].Index = map[index];
232          }
233       }
234       if (inst->DstReg.File == file) {
235          const GLuint index = inst->DstReg.Index;
236          ASSERT(map[index] >= 0);
237          inst->DstReg.Index = map[index];
238       }
239    }
240 }
241
242
243 /**
244  * Remove dead instructions from the given program.
245  * This is very primitive for now.  Basically look for temp registers
246  * that are written to but never read.  Remove any instructions that
247  * write to such registers.  Be careful with condition code setters.
248  */
249 static GLboolean
250 _mesa_remove_dead_code_global(struct gl_program *prog)
251 {
252    GLboolean tempRead[REG_ALLOCATE_MAX_PROGRAM_TEMPS][4];
253    GLboolean *removeInst; /* per-instruction removal flag */
254    GLuint i, rem = 0, comp;
255
256    memset(tempRead, 0, sizeof(tempRead));
257
258    if (dbg) {
259       printf("Optimize: Begin dead code removal\n");
260       /*_mesa_print_program(prog);*/
261    }
262
263    removeInst =
264       calloc(1, prog->NumInstructions * sizeof(GLboolean));
265
266    /* Determine which temps are read and written */
267    for (i = 0; i < prog->NumInstructions; i++) {
268       const struct prog_instruction *inst = prog->Instructions + i;
269       const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
270       GLuint j;
271
272       /* check src regs */
273       for (j = 0; j < numSrc; j++) {
274          if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) {
275             const GLuint index = inst->SrcReg[j].Index;
276             GLuint read_mask;
277             ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS);
278             read_mask = get_src_arg_mask(inst, j, NO_MASK);
279
280             if (inst->SrcReg[j].RelAddr) {
281                if (dbg)
282                   printf("abort remove dead code (indirect temp)\n");
283                goto done;
284             }
285
286             for (comp = 0; comp < 4; comp++) {
287                const GLuint swz = GET_SWZ(inst->SrcReg[j].Swizzle, comp);
288                ASSERT(swz < 4);
289                if ((read_mask & (1 << swz)) == 0)
290                   continue;
291                if (swz <= SWIZZLE_W)
292                   tempRead[index][swz] = GL_TRUE;
293             }
294          }
295       }
296
297       /* check dst reg */
298       if (inst->DstReg.File == PROGRAM_TEMPORARY) {
299          const GLuint index = inst->DstReg.Index;
300          ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS);
301
302          if (inst->DstReg.RelAddr) {
303             if (dbg)
304                printf("abort remove dead code (indirect temp)\n");
305             goto done;
306          }
307
308          if (inst->CondUpdate) {
309             /* If we're writing to this register and setting condition
310              * codes we cannot remove the instruction.  Prevent removal
311              * by setting the 'read' flag.
312              */
313             tempRead[index][0] = GL_TRUE;
314             tempRead[index][1] = GL_TRUE;
315             tempRead[index][2] = GL_TRUE;
316             tempRead[index][3] = GL_TRUE;
317          }
318       }
319    }
320
321    /* find instructions that write to dead registers, flag for removal */
322    for (i = 0; i < prog->NumInstructions; i++) {
323       struct prog_instruction *inst = prog->Instructions + i;
324       const GLuint numDst = _mesa_num_inst_dst_regs(inst->Opcode);
325
326       if (numDst != 0 && inst->DstReg.File == PROGRAM_TEMPORARY) {
327          GLint chan, index = inst->DstReg.Index;
328
329          for (chan = 0; chan < 4; chan++) {
330             if (!tempRead[index][chan] &&
331                 inst->DstReg.WriteMask & (1 << chan)) {
332                if (dbg) {
333                   printf("Remove writemask on %u.%c\n", i,
334                                chan == 3 ? 'w' : 'x' + chan);
335                }
336                inst->DstReg.WriteMask &= ~(1 << chan);
337                rem++;
338             }
339          }
340
341          if (inst->DstReg.WriteMask == 0) {
342             /* If we cleared all writes, the instruction can be removed. */
343             if (dbg)
344                printf("Remove instruction %u: \n", i);
345             removeInst[i] = GL_TRUE;
346          }
347       }
348    }
349
350    /* now remove the instructions which aren't needed */
351    rem = remove_instructions(prog, removeInst);
352
353    if (dbg) {
354       printf("Optimize: End dead code removal.\n");
355       printf("  %u channel writes removed\n", rem);
356       printf("  %u instructions removed\n", rem);
357       /*_mesa_print_program(prog);*/
358    }
359
360 done:
361    free(removeInst);
362    return rem != 0;
363 }
364
365
366 enum inst_use
367 {
368    READ,
369    WRITE,
370    FLOW,
371    END
372 };
373
374
375 /**
376  * Scan forward in program from 'start' for the next occurances of TEMP[index].
377  * We look if an instruction reads the component given by the masks and if they
378  * are overwritten.
379  * Return READ, WRITE, FLOW or END to indicate the next usage or an indicator
380  * that we can't look further.
381  */
382 static enum inst_use
383 find_next_use(const struct gl_program *prog,
384               GLuint start,
385               GLuint index,
386               GLuint mask)
387 {
388    GLuint i;
389
390    for (i = start; i < prog->NumInstructions; i++) {
391       const struct prog_instruction *inst = prog->Instructions + i;
392       switch (inst->Opcode) {
393       case OPCODE_BGNLOOP:
394       case OPCODE_BGNSUB:
395       case OPCODE_CAL:
396       case OPCODE_CONT:
397       case OPCODE_IF:
398       case OPCODE_ELSE:
399       case OPCODE_ENDIF:
400       case OPCODE_ENDLOOP:
401       case OPCODE_ENDSUB:
402       case OPCODE_RET:
403          return FLOW;
404       case OPCODE_END:
405          return END;
406       default:
407          {
408             const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
409             GLuint j;
410             for (j = 0; j < numSrc; j++) {
411                if (inst->SrcReg[j].RelAddr ||
412                    (inst->SrcReg[j].File == PROGRAM_TEMPORARY &&
413                    inst->SrcReg[j].Index == index &&
414                    (get_src_arg_mask(inst,j,NO_MASK) & mask)))
415                   return READ;
416             }
417             if (_mesa_num_inst_dst_regs(inst->Opcode) == 1 &&
418                 inst->DstReg.File == PROGRAM_TEMPORARY &&
419                 inst->DstReg.Index == index) {
420                mask &= ~inst->DstReg.WriteMask;
421                if (mask == 0)
422                   return WRITE;
423             }
424          }
425       }
426    }
427    return END;
428 }
429
430
431 /**
432  * Is the given instruction opcode a flow-control opcode?
433  * XXX maybe move this into prog_instruction.[ch]
434  */
435 static GLboolean
436 _mesa_is_flow_control_opcode(enum prog_opcode opcode)
437 {
438    switch (opcode) {
439    case OPCODE_BGNLOOP:
440    case OPCODE_BGNSUB:
441    case OPCODE_CAL:
442    case OPCODE_CONT:
443    case OPCODE_IF:
444    case OPCODE_ELSE:
445    case OPCODE_END:
446    case OPCODE_ENDIF:
447    case OPCODE_ENDLOOP:
448    case OPCODE_ENDSUB:
449    case OPCODE_RET:
450       return GL_TRUE;
451    default:
452       return GL_FALSE;
453    }
454 }
455
456
457 /**
458  * Test if the given instruction is a simple MOV (no conditional updating,
459  * not relative addressing, no negation/abs, etc).
460  */
461 static GLboolean
462 can_downward_mov_be_modifed(const struct prog_instruction *mov)
463 {
464    return
465       mov->Opcode == OPCODE_MOV &&
466       mov->CondUpdate == GL_FALSE &&
467       mov->SrcReg[0].RelAddr == 0 &&
468       mov->SrcReg[0].Negate == 0 &&
469       mov->SrcReg[0].Abs == 0 &&
470       mov->SrcReg[0].HasIndex2 == 0 &&
471       mov->SrcReg[0].RelAddr2 == 0 &&
472       mov->DstReg.RelAddr == 0 &&
473       mov->DstReg.CondMask == COND_TR;
474 }
475
476
477 static GLboolean
478 can_upward_mov_be_modifed(const struct prog_instruction *mov)
479 {
480    return
481       can_downward_mov_be_modifed(mov) &&
482       mov->DstReg.File == PROGRAM_TEMPORARY &&
483       mov->SaturateMode == SATURATE_OFF;
484 }
485
486
487 /**
488  * Try to remove use of extraneous MOV instructions, to free them up for dead
489  * code removal.
490  */
491 static void
492 _mesa_remove_extra_move_use(struct gl_program *prog)
493 {
494    GLuint i, j;
495
496    if (dbg) {
497       printf("Optimize: Begin remove extra move use\n");
498       _mesa_print_program(prog);
499    }
500
501    /*
502     * Look for sequences such as this:
503     *    MOV tmpX, arg0;
504     *    ...
505     *    FOO tmpY, tmpX, arg1;
506     * and convert into:
507     *    MOV tmpX, arg0;
508     *    ...
509     *    FOO tmpY, arg0, arg1;
510     */
511
512    for (i = 0; i + 1 < prog->NumInstructions; i++) {
513       const struct prog_instruction *mov = prog->Instructions + i;
514       GLuint dst_mask, src_mask;
515       if (can_upward_mov_be_modifed(mov) == GL_FALSE)
516          continue;
517
518       /* Scanning the code, we maintain the components which are still active in
519        * these two masks
520        */
521       dst_mask = mov->DstReg.WriteMask;
522       src_mask = get_src_arg_mask(mov, 0, NO_MASK);
523
524       /* Walk through remaining instructions until the or src reg gets
525        * rewritten or we get into some flow-control, eliminating the use of
526        * this MOV.
527        */
528       for (j = i + 1; j < prog->NumInstructions; j++) {
529          struct prog_instruction *inst2 = prog->Instructions + j;
530          GLuint arg;
531
532          if (_mesa_is_flow_control_opcode(inst2->Opcode))
533              break;
534
535          /* First rewrite this instruction's args if appropriate. */
536          for (arg = 0; arg < _mesa_num_inst_src_regs(inst2->Opcode); arg++) {
537             GLuint comp, read_mask;
538
539             if (inst2->SrcReg[arg].File != mov->DstReg.File ||
540                 inst2->SrcReg[arg].Index != mov->DstReg.Index ||
541                 inst2->SrcReg[arg].RelAddr ||
542                 inst2->SrcReg[arg].Abs)
543                continue;
544             read_mask = get_src_arg_mask(inst2, arg, NO_MASK);
545
546             /* Adjust the swizzles of inst2 to point at MOV's source if ALL the
547              * components read still come from the mov instructions
548              */
549             if (is_swizzle_regular(inst2->SrcReg[arg].Swizzle) &&
550                (read_mask & dst_mask) == read_mask) {
551                for (comp = 0; comp < 4; comp++) {
552                   const GLuint inst2_swz =
553                      GET_SWZ(inst2->SrcReg[arg].Swizzle, comp);
554                   const GLuint s = GET_SWZ(mov->SrcReg[0].Swizzle, inst2_swz);
555                   inst2->SrcReg[arg].Swizzle &= ~(7 << (3 * comp));
556                   inst2->SrcReg[arg].Swizzle |= s << (3 * comp);
557                   inst2->SrcReg[arg].Negate ^= (((mov->SrcReg[0].Negate >>
558                                                   inst2_swz) & 0x1) << comp);
559                }
560                inst2->SrcReg[arg].File = mov->SrcReg[0].File;
561                inst2->SrcReg[arg].Index = mov->SrcReg[0].Index;
562             }
563          }
564
565          /* The source of MOV is written. This potentially deactivates some
566           * components from the src and dst of the MOV instruction
567           */
568          if (inst2->DstReg.File == mov->DstReg.File &&
569              (inst2->DstReg.RelAddr ||
570               inst2->DstReg.Index == mov->DstReg.Index)) {
571             dst_mask &= ~inst2->DstReg.WriteMask;
572             src_mask = get_src_arg_mask(mov, 0, dst_mask);
573          }
574
575          /* Idem when the destination of mov is written */
576          if (inst2->DstReg.File == mov->SrcReg[0].File &&
577              (inst2->DstReg.RelAddr ||
578               inst2->DstReg.Index == mov->SrcReg[0].Index)) {
579             src_mask &= ~inst2->DstReg.WriteMask;
580             dst_mask &= get_dst_mask_for_mov(mov, src_mask);
581          }
582          if (dst_mask == 0)
583             break;
584       }
585    }
586
587    if (dbg) {
588       printf("Optimize: End remove extra move use.\n");
589       /*_mesa_print_program(prog);*/
590    }
591 }
592
593
594 /**
595  * Complements dead_code_global. Try to remove code in block of code by
596  * carefully monitoring the swizzles. Both functions should be merged into one
597  * with a proper control flow graph
598  */
599 static GLboolean
600 _mesa_remove_dead_code_local(struct gl_program *prog)
601 {
602    GLboolean *removeInst;
603    GLuint i, arg, rem = 0;
604
605    removeInst =
606       calloc(1, prog->NumInstructions * sizeof(GLboolean));
607
608    for (i = 0; i < prog->NumInstructions; i++) {
609       const struct prog_instruction *inst = prog->Instructions + i;
610       const GLuint index = inst->DstReg.Index;
611       const GLuint mask = inst->DstReg.WriteMask;
612       enum inst_use use;
613
614       /* We must deactivate the pass as soon as some indirection is used */
615       if (inst->DstReg.RelAddr)
616          goto done;
617       for (arg = 0; arg < _mesa_num_inst_src_regs(inst->Opcode); arg++)
618          if (inst->SrcReg[arg].RelAddr)
619             goto done;
620
621       if (_mesa_is_flow_control_opcode(inst->Opcode) ||
622           _mesa_num_inst_dst_regs(inst->Opcode) == 0 ||
623           inst->DstReg.File != PROGRAM_TEMPORARY ||
624           inst->DstReg.RelAddr)
625          continue;
626
627       use = find_next_use(prog, i+1, index, mask);
628       if (use == WRITE || use == END)
629          removeInst[i] = GL_TRUE;
630    }
631
632    rem = remove_instructions(prog, removeInst);
633
634 done:
635    free(removeInst);
636    return rem != 0;
637 }
638
639
640 /**
641  * Try to inject the destination of mov as the destination of inst and recompute
642  * the swizzles operators for the sources of inst if required. Return GL_TRUE
643  * of the substitution was possible, GL_FALSE otherwise
644  */
645 static GLboolean
646 _mesa_merge_mov_into_inst(struct prog_instruction *inst,
647                           const struct prog_instruction *mov)
648 {
649    /* Indirection table which associates destination and source components for
650     * the mov instruction
651     */
652    const GLuint mask = get_src_arg_mask(mov, 0, NO_MASK);
653
654    /* Some components are not written by inst. We cannot remove the mov */
655    if (mask != (inst->DstReg.WriteMask & mask))
656       return GL_FALSE;
657
658    inst->SaturateMode |= mov->SaturateMode;
659
660    /* Depending on the instruction, we may need to recompute the swizzles.
661     * Also, some other instructions (like TEX) are not linear. We will only
662     * consider completely active sources and destinations
663     */
664    switch (inst->Opcode) {
665
666    /* Carstesian instructions: we compute the swizzle */
667    case OPCODE_MOV:
668    case OPCODE_MIN:
669    case OPCODE_MAX:
670    case OPCODE_ABS:
671    case OPCODE_ADD:
672    case OPCODE_MAD:
673    case OPCODE_MUL:
674    case OPCODE_SUB:
675    {
676       GLuint dst_to_src_comp[4] = {0,0,0,0};
677       GLuint dst_comp, arg;
678       for (dst_comp = 0; dst_comp < 4; ++dst_comp) {
679          if (mov->DstReg.WriteMask & (1 << dst_comp)) {
680             const GLuint src_comp = GET_SWZ(mov->SrcReg[0].Swizzle, dst_comp);
681             ASSERT(src_comp < 4);
682             dst_to_src_comp[dst_comp] = src_comp;
683          }
684       }
685
686       /* Patch each source of the instruction */
687       for (arg = 0; arg < _mesa_num_inst_src_regs(inst->Opcode); arg++) {
688          const GLuint arg_swz = inst->SrcReg[arg].Swizzle;
689          inst->SrcReg[arg].Swizzle = 0;
690
691          /* Reset each active component of the swizzle */
692          for (dst_comp = 0; dst_comp < 4; ++dst_comp) {
693             GLuint src_comp, arg_comp;
694             if ((mov->DstReg.WriteMask & (1 << dst_comp)) == 0)
695                continue;
696             src_comp = dst_to_src_comp[dst_comp];
697             ASSERT(src_comp < 4);
698             arg_comp = GET_SWZ(arg_swz, src_comp);
699             ASSERT(arg_comp < 4);
700             inst->SrcReg[arg].Swizzle |= arg_comp << (3*dst_comp);
701          }
702       }
703       inst->DstReg = mov->DstReg;
704       return GL_TRUE;
705    }
706
707    /* Dot products and scalar instructions: we only change the destination */
708    case OPCODE_RCP:
709    case OPCODE_SIN:
710    case OPCODE_COS:
711    case OPCODE_RSQ:
712    case OPCODE_POW:
713    case OPCODE_EX2:
714    case OPCODE_LOG:
715    case OPCODE_DP2:
716    case OPCODE_DP3:
717    case OPCODE_DP4:
718       inst->DstReg = mov->DstReg;
719       return GL_TRUE;
720
721    /* All other instructions require fully active components with no swizzle */
722    default:
723       if (mov->SrcReg[0].Swizzle != SWIZZLE_XYZW ||
724           inst->DstReg.WriteMask != WRITEMASK_XYZW)
725          return GL_FALSE;
726       inst->DstReg = mov->DstReg;
727       return GL_TRUE;
728    }
729 }
730
731
732 /**
733  * Try to remove extraneous MOV instructions from the given program.
734  */
735 static GLboolean
736 _mesa_remove_extra_moves(struct gl_program *prog)
737 {
738    GLboolean *removeInst; /* per-instruction removal flag */
739    GLuint i, rem = 0, nesting = 0;
740
741    if (dbg) {
742       printf("Optimize: Begin remove extra moves\n");
743       _mesa_print_program(prog);
744    }
745
746    removeInst =
747       calloc(1, prog->NumInstructions * sizeof(GLboolean));
748
749    /*
750     * Look for sequences such as this:
751     *    FOO tmpX, arg0, arg1;
752     *    MOV tmpY, tmpX;
753     * and convert into:
754     *    FOO tmpY, arg0, arg1;
755     */
756
757    for (i = 0; i < prog->NumInstructions; i++) {
758       const struct prog_instruction *mov = prog->Instructions + i;
759
760       switch (mov->Opcode) {
761       case OPCODE_BGNLOOP:
762       case OPCODE_BGNSUB:
763       case OPCODE_IF:
764          nesting++;
765          break;
766       case OPCODE_ENDLOOP:
767       case OPCODE_ENDSUB:
768       case OPCODE_ENDIF:
769          nesting--;
770          break;
771       case OPCODE_MOV:
772          if (i > 0 &&
773              can_downward_mov_be_modifed(mov) &&
774              mov->SrcReg[0].File == PROGRAM_TEMPORARY &&
775              nesting == 0)
776          {
777
778             /* see if this MOV can be removed */
779             const GLuint id = mov->SrcReg[0].Index;
780             struct prog_instruction *prevInst;
781             GLuint prevI;
782
783             /* get pointer to previous instruction */
784             prevI = i - 1;
785             while (prevI > 0 && removeInst[prevI])
786                prevI--;
787             prevInst = prog->Instructions + prevI;
788
789             if (prevInst->DstReg.File == PROGRAM_TEMPORARY &&
790                 prevInst->DstReg.Index == id &&
791                 prevInst->DstReg.RelAddr == 0 &&
792                 prevInst->DstReg.CondMask == COND_TR) {
793
794                const GLuint dst_mask = prevInst->DstReg.WriteMask;
795                enum inst_use next_use = find_next_use(prog, i+1, id, dst_mask);
796
797                if (next_use == WRITE || next_use == END) {
798                   /* OK, we can safely remove this MOV instruction.
799                    * Transform:
800                    *   prevI: FOO tempIndex, x, y;
801                    *       i: MOV z, tempIndex;
802                    * Into:
803                    *   prevI: FOO z, x, y;
804                    */
805                   if (_mesa_merge_mov_into_inst(prevInst, mov)) {
806                      removeInst[i] = GL_TRUE;
807                      if (dbg) {
808                         printf("Remove MOV at %u\n", i);
809                         printf("new prev inst %u: ", prevI);
810                         _mesa_print_instruction(prevInst);
811                      }
812                   }
813                }
814             }
815          }
816          break;
817       default:
818          ; /* nothing */
819       }
820    }
821
822    /* now remove the instructions which aren't needed */
823    rem = remove_instructions(prog, removeInst);
824
825    free(removeInst);
826
827    if (dbg) {
828       printf("Optimize: End remove extra moves.  %u instructions removed\n", rem);
829       /*_mesa_print_program(prog);*/
830    }
831
832    return rem != 0;
833 }
834
835
836 /** A live register interval */
837 struct interval
838 {
839    GLuint Reg;         /** The temporary register index */
840    GLuint Start, End;  /** Start/end instruction numbers */
841 };
842
843
844 /** A list of register intervals */
845 struct interval_list
846 {
847    GLuint Num;
848    struct interval Intervals[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
849 };
850
851
852 static void
853 append_interval(struct interval_list *list, const struct interval *inv)
854 {
855    list->Intervals[list->Num++] = *inv;
856 }
857
858
859 /** Insert interval inv into list, sorted by interval end */
860 static void
861 insert_interval_by_end(struct interval_list *list, const struct interval *inv)
862 {
863    /* XXX we could do a binary search insertion here since list is sorted */
864    GLint i = list->Num - 1;
865    while (i >= 0 && list->Intervals[i].End > inv->End) {
866       list->Intervals[i + 1] = list->Intervals[i];
867       i--;
868    }
869    list->Intervals[i + 1] = *inv;
870    list->Num++;
871
872 #ifdef DEBUG
873    {
874       GLuint i;
875       for (i = 0; i + 1 < list->Num; i++) {
876          ASSERT(list->Intervals[i].End <= list->Intervals[i + 1].End);
877       }
878    }
879 #endif
880 }
881
882
883 /** Remove the given interval from the interval list */
884 static void
885 remove_interval(struct interval_list *list, const struct interval *inv)
886 {
887    /* XXX we could binary search since list is sorted */
888    GLuint k;
889    for (k = 0; k < list->Num; k++) {
890       if (list->Intervals[k].Reg == inv->Reg) {
891          /* found, remove it */
892          ASSERT(list->Intervals[k].Start == inv->Start);
893          ASSERT(list->Intervals[k].End == inv->End);
894          while (k < list->Num - 1) {
895             list->Intervals[k] = list->Intervals[k + 1];
896             k++;
897          }
898          list->Num--;
899          return;
900       }
901    }
902 }
903
904
905 /** called by qsort() */
906 static int
907 compare_start(const void *a, const void *b)
908 {
909    const struct interval *ia = (const struct interval *) a;
910    const struct interval *ib = (const struct interval *) b;
911    if (ia->Start < ib->Start)
912       return -1;
913    else if (ia->Start > ib->Start)
914       return +1;
915    else
916       return 0;
917 }
918
919
920 /** sort the interval list according to interval starts */
921 static void
922 sort_interval_list_by_start(struct interval_list *list)
923 {
924    qsort(list->Intervals, list->Num, sizeof(struct interval), compare_start);
925 #ifdef DEBUG
926    {
927       GLuint i;
928       for (i = 0; i + 1 < list->Num; i++) {
929          ASSERT(list->Intervals[i].Start <= list->Intervals[i + 1].Start);
930       }
931    }
932 #endif
933 }
934
935 struct loop_info
936 {
937    GLuint Start, End;  /**< Start, end instructions of loop */
938 };
939
940 /**
941  * Update the intermediate interval info for register 'index' and
942  * instruction 'ic'.
943  */
944 static void
945 update_interval(GLint intBegin[], GLint intEnd[],
946                 struct loop_info *loopStack, GLuint loopStackDepth,
947                 GLuint index, GLuint ic)
948 {
949    int i;
950    GLuint begin = ic;
951    GLuint end = ic;
952
953    /* If the register is used in a loop, extend its lifetime through the end
954     * of the outermost loop that doesn't contain its definition.
955     */
956    for (i = 0; i < loopStackDepth; i++) {
957       if (intBegin[index] < loopStack[i].Start) {
958          end = loopStack[i].End;
959          break;
960       }
961    }
962
963    /* Variables that are live at the end of a loop will also be live at the
964     * beginning, so an instruction inside of a loop should have its live
965     * interval begin at the start of the outermost loop.
966     */
967    if (loopStackDepth > 0 && ic > loopStack[0].Start && ic < loopStack[0].End) {
968       begin = loopStack[0].Start;
969    }
970
971    ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS);
972    if (intBegin[index] == -1) {
973       ASSERT(intEnd[index] == -1);
974       intBegin[index] = begin;
975       intEnd[index] = end;
976    }
977    else {
978       intEnd[index] = end;
979    }
980 }
981
982
983 /**
984  * Find first/last instruction that references each temporary register.
985  */
986 GLboolean
987 _mesa_find_temp_intervals(const struct prog_instruction *instructions,
988                           GLuint numInstructions,
989                           GLint intBegin[REG_ALLOCATE_MAX_PROGRAM_TEMPS],
990                           GLint intEnd[REG_ALLOCATE_MAX_PROGRAM_TEMPS])
991 {
992    struct loop_info loopStack[MAX_LOOP_NESTING];
993    GLuint loopStackDepth = 0;
994    GLuint i;
995
996    for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++){
997       intBegin[i] = intEnd[i] = -1;
998    }
999
1000    /* Scan instructions looking for temporary registers */
1001    for (i = 0; i < numInstructions; i++) {
1002       const struct prog_instruction *inst = instructions + i;
1003       if (inst->Opcode == OPCODE_BGNLOOP) {
1004          loopStack[loopStackDepth].Start = i;
1005          loopStack[loopStackDepth].End = inst->BranchTarget;
1006          loopStackDepth++;
1007       }
1008       else if (inst->Opcode == OPCODE_ENDLOOP) {
1009          loopStackDepth--;
1010       }
1011       else if (inst->Opcode == OPCODE_CAL) {
1012          return GL_FALSE;
1013       }
1014       else {
1015          const GLuint numSrc = 3;/*_mesa_num_inst_src_regs(inst->Opcode);*/
1016          GLuint j;
1017          for (j = 0; j < numSrc; j++) {
1018             if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) {
1019                const GLuint index = inst->SrcReg[j].Index;
1020                if (inst->SrcReg[j].RelAddr)
1021                   return GL_FALSE;
1022                update_interval(intBegin, intEnd, loopStack, loopStackDepth,
1023                                index, i);
1024             }
1025          }
1026          if (inst->DstReg.File == PROGRAM_TEMPORARY) {
1027             const GLuint index = inst->DstReg.Index;
1028             if (inst->DstReg.RelAddr)
1029                return GL_FALSE;
1030             update_interval(intBegin, intEnd, loopStack, loopStackDepth,
1031                             index, i);
1032          }
1033       }
1034    }
1035
1036    return GL_TRUE;
1037 }
1038
1039
1040 /**
1041  * Find the live intervals for each temporary register in the program.
1042  * For register R, the interval [A,B] indicates that R is referenced
1043  * from instruction A through instruction B.
1044  * Special consideration is needed for loops and subroutines.
1045  * \return GL_TRUE if success, GL_FALSE if we cannot proceed for some reason
1046  */
1047 static GLboolean
1048 find_live_intervals(struct gl_program *prog,
1049                     struct interval_list *liveIntervals)
1050 {
1051    GLint intBegin[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
1052    GLint intEnd[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
1053    GLuint i;
1054
1055    /*
1056     * Note: we'll return GL_FALSE below if we find relative indexing
1057     * into the TEMP register file.  We can't handle that yet.
1058     * We also give up on subroutines for now.
1059     */
1060
1061    if (dbg) {
1062       printf("Optimize: Begin find intervals\n");
1063    }
1064
1065    /* build intermediate arrays */
1066    if (!_mesa_find_temp_intervals(prog->Instructions, prog->NumInstructions,
1067                                   intBegin, intEnd))
1068       return GL_FALSE;
1069
1070    /* Build live intervals list from intermediate arrays */
1071    liveIntervals->Num = 0;
1072    for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++) {
1073       if (intBegin[i] >= 0) {
1074          struct interval inv;
1075          inv.Reg = i;
1076          inv.Start = intBegin[i];
1077          inv.End = intEnd[i];
1078          append_interval(liveIntervals, &inv);
1079       }
1080    }
1081
1082    /* Sort the list according to interval starts */
1083    sort_interval_list_by_start(liveIntervals);
1084
1085    if (dbg) {
1086       /* print interval info */
1087       for (i = 0; i < liveIntervals->Num; i++) {
1088          const struct interval *inv = liveIntervals->Intervals + i;
1089          printf("Reg[%d] live [%d, %d]:",
1090                       inv->Reg, inv->Start, inv->End);
1091          if (1) {
1092             GLuint j;
1093             for (j = 0; j < inv->Start; j++)
1094                printf(" ");
1095             for (j = inv->Start; j <= inv->End; j++)
1096                printf("x");
1097          }
1098          printf("\n");
1099       }
1100    }
1101
1102    return GL_TRUE;
1103 }
1104
1105
1106 /** Scan the array of used register flags to find free entry */
1107 static GLint
1108 alloc_register(GLboolean usedRegs[REG_ALLOCATE_MAX_PROGRAM_TEMPS])
1109 {
1110    GLuint k;
1111    for (k = 0; k < REG_ALLOCATE_MAX_PROGRAM_TEMPS; k++) {
1112       if (!usedRegs[k]) {
1113          usedRegs[k] = GL_TRUE;
1114          return k;
1115       }
1116    }
1117    return -1;
1118 }
1119
1120
1121 /**
1122  * This function implements "Linear Scan Register Allocation" to reduce
1123  * the number of temporary registers used by the program.
1124  *
1125  * We compute the "live interval" for all temporary registers then
1126  * examine the overlap of the intervals to allocate new registers.
1127  * Basically, if two intervals do not overlap, they can use the same register.
1128  */
1129 static void
1130 _mesa_reallocate_registers(struct gl_program *prog)
1131 {
1132    struct interval_list liveIntervals;
1133    GLint registerMap[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
1134    GLboolean usedRegs[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
1135    GLuint i;
1136    GLint maxTemp = -1;
1137
1138    if (dbg) {
1139       printf("Optimize: Begin live-interval register reallocation\n");
1140       _mesa_print_program(prog);
1141    }
1142
1143    for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++){
1144       registerMap[i] = -1;
1145       usedRegs[i] = GL_FALSE;
1146    }
1147
1148    if (!find_live_intervals(prog, &liveIntervals)) {
1149       if (dbg)
1150          printf("Aborting register reallocation\n");
1151       return;
1152    }
1153
1154    {
1155       struct interval_list activeIntervals;
1156       activeIntervals.Num = 0;
1157
1158       /* loop over live intervals, allocating a new register for each */
1159       for (i = 0; i < liveIntervals.Num; i++) {
1160          const struct interval *live = liveIntervals.Intervals + i;
1161
1162          if (dbg)
1163             printf("Consider register %u\n", live->Reg);
1164
1165          /* Expire old intervals.  Intervals which have ended with respect
1166           * to the live interval can have their remapped registers freed.
1167           */
1168          {
1169             GLint j;
1170             for (j = 0; j < (GLint) activeIntervals.Num; j++) {
1171                const struct interval *inv = activeIntervals.Intervals + j;
1172                if (inv->End >= live->Start) {
1173                   /* Stop now.  Since the activeInterval list is sorted
1174                    * we know we don't have to go further.
1175                    */
1176                   break;
1177                }
1178                else {
1179                   /* Interval 'inv' has expired */
1180                   const GLint regNew = registerMap[inv->Reg];
1181                   ASSERT(regNew >= 0);
1182
1183                   if (dbg)
1184                      printf("  expire interval for reg %u\n", inv->Reg);
1185
1186                   /* remove interval j from active list */
1187                   remove_interval(&activeIntervals, inv);
1188                   j--;  /* counter-act j++ in for-loop above */
1189
1190                   /* return register regNew to the free pool */
1191                   if (dbg)
1192                      printf("  free reg %d\n", regNew);
1193                   ASSERT(usedRegs[regNew] == GL_TRUE);
1194                   usedRegs[regNew] = GL_FALSE;
1195                }
1196             }
1197          }
1198
1199          /* find a free register for this live interval */
1200          {
1201             const GLint k = alloc_register(usedRegs);
1202             if (k < 0) {
1203                /* out of registers, give up */
1204                return;
1205             }
1206             registerMap[live->Reg] = k;
1207             maxTemp = MAX2(maxTemp, k);
1208             if (dbg)
1209                printf("  remap register %u -> %d\n", live->Reg, k);
1210          }
1211
1212          /* Insert this live interval into the active list which is sorted
1213           * by increasing end points.
1214           */
1215          insert_interval_by_end(&activeIntervals, live);
1216       }
1217    }
1218
1219    if (maxTemp + 1 < (GLint) liveIntervals.Num) {
1220       /* OK, we've reduced the number of registers needed.
1221        * Scan the program and replace all the old temporary register
1222        * indexes with the new indexes.
1223        */
1224       replace_regs(prog, PROGRAM_TEMPORARY, registerMap);
1225
1226       prog->NumTemporaries = maxTemp + 1;
1227    }
1228
1229    if (dbg) {
1230       printf("Optimize: End live-interval register reallocation\n");
1231       printf("Num temp regs before: %u  after: %u\n",
1232                    liveIntervals.Num, maxTemp + 1);
1233       _mesa_print_program(prog);
1234    }
1235 }
1236
1237
1238 #if 0
1239 static void
1240 print_it(struct gl_context *ctx, struct gl_program *program, const char *txt) {
1241    fprintf(stderr, "%s (%u inst):\n", txt, program->NumInstructions);
1242    _mesa_print_program(program);
1243    _mesa_print_program_parameters(ctx, program);
1244    fprintf(stderr, "\n\n");
1245 }
1246 #endif
1247
1248 /**
1249  * This pass replaces CMP T0, T1 T2 T0 with MOV T0, T2 when the CMP
1250  * instruction is the first instruction to write to register T0.  The are
1251  * several lowering passes done in GLSL IR (e.g. branches and
1252  * relative addressing) that create a large number of conditional assignments
1253  * that ir_to_mesa converts to CMP instructions like the one mentioned above.
1254  *
1255  * Here is why this conversion is safe:
1256  * CMP T0, T1 T2 T0 can be expanded to:
1257  * if (T1 < 0.0)
1258  *      MOV T0, T2;
1259  * else
1260  *      MOV T0, T0;
1261  *
1262  * If (T1 < 0.0) evaluates to true then our replacement MOV T0, T2 is the same
1263  * as the original program.  If (T1 < 0.0) evaluates to false, executing
1264  * MOV T0, T0 will store a garbage value in T0 since T0 is uninitialized.
1265  * Therefore, it doesn't matter that we are replacing MOV T0, T0 with MOV T0, T2
1266  * because any instruction that was going to read from T0 after this was going
1267  * to read a garbage value anyway.
1268  */
1269 static void
1270 _mesa_simplify_cmp(struct gl_program * program)
1271 {
1272    GLuint tempWrites[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
1273    GLuint outputWrites[MAX_PROGRAM_OUTPUTS];
1274    GLuint i;
1275
1276    if (dbg) {
1277       printf("Optimize: Begin reads without writes\n");
1278       _mesa_print_program(program);
1279    }
1280
1281    for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++) {
1282       tempWrites[i] = 0;
1283    }
1284
1285    for (i = 0; i < MAX_PROGRAM_OUTPUTS; i++) {
1286       outputWrites[i] = 0;
1287    }
1288
1289    for (i = 0; i < program->NumInstructions; i++) {
1290       struct prog_instruction *inst = program->Instructions + i;
1291       GLuint prevWriteMask;
1292
1293       /* Give up if we encounter relative addressing or flow control. */
1294       if (_mesa_is_flow_control_opcode(inst->Opcode) || inst->DstReg.RelAddr) {
1295          return;
1296       }
1297
1298       if (inst->DstReg.File == PROGRAM_OUTPUT) {
1299          assert(inst->DstReg.Index < MAX_PROGRAM_OUTPUTS);
1300          prevWriteMask = outputWrites[inst->DstReg.Index];
1301          outputWrites[inst->DstReg.Index] |= inst->DstReg.WriteMask;
1302       } else if (inst->DstReg.File == PROGRAM_TEMPORARY) {
1303          assert(inst->DstReg.Index < REG_ALLOCATE_MAX_PROGRAM_TEMPS);
1304          prevWriteMask = tempWrites[inst->DstReg.Index];
1305          tempWrites[inst->DstReg.Index] |= inst->DstReg.WriteMask;
1306       } else {
1307          /* No other register type can be a destination register. */
1308          continue;
1309       }
1310
1311       /* For a CMP to be considered a conditional write, the destination
1312        * register and source register two must be the same. */
1313       if (inst->Opcode == OPCODE_CMP
1314           && !(inst->DstReg.WriteMask & prevWriteMask)
1315           && inst->SrcReg[2].File == inst->DstReg.File
1316           && inst->SrcReg[2].Index == inst->DstReg.Index
1317           && inst->DstReg.WriteMask == get_src_arg_mask(inst, 2, NO_MASK)) {
1318
1319          inst->Opcode = OPCODE_MOV;
1320          inst->SrcReg[0] = inst->SrcReg[1];
1321
1322          /* Unused operands are expected to have the file set to
1323           * PROGRAM_UNDEFINED.  This is how _mesa_init_instructions initializes
1324           * all of the sources.
1325           */
1326          inst->SrcReg[1].File = PROGRAM_UNDEFINED;
1327          inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
1328          inst->SrcReg[2].File = PROGRAM_UNDEFINED;
1329          inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
1330       }
1331    }
1332    if (dbg) {
1333       printf("Optimize: End reads without writes\n");
1334       _mesa_print_program(program);
1335    }
1336 }
1337
1338 /**
1339  * Apply optimizations to the given program to eliminate unnecessary
1340  * instructions, temp regs, etc.
1341  */
1342 void
1343 _mesa_optimize_program(struct gl_context *ctx, struct gl_program *program)
1344 {
1345    GLboolean any_change;
1346
1347    _mesa_simplify_cmp(program);
1348    /* Stop when no modifications were output */
1349    do {
1350       any_change = GL_FALSE;
1351       _mesa_remove_extra_move_use(program);
1352       if (_mesa_remove_dead_code_global(program))
1353          any_change = GL_TRUE;
1354       if (_mesa_remove_extra_moves(program))
1355          any_change = GL_TRUE;
1356       if (_mesa_remove_dead_code_local(program))
1357          any_change = GL_TRUE;
1358
1359       any_change = _mesa_constant_fold(program) || any_change;
1360       _mesa_reallocate_registers(program);
1361    } while (any_change);
1362 }
1363