Tizen 2.0 Release
[profile/ivi/osmesa.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 = (GLboolean *)
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_BRA:
396       case OPCODE_CAL:
397       case OPCODE_CONT:
398       case OPCODE_IF:
399       case OPCODE_ELSE:
400       case OPCODE_ENDIF:
401       case OPCODE_ENDLOOP:
402       case OPCODE_ENDSUB:
403       case OPCODE_RET:
404          return FLOW;
405       case OPCODE_END:
406          return END;
407       default:
408          {
409             const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
410             GLuint j;
411             for (j = 0; j < numSrc; j++) {
412                if (inst->SrcReg[j].RelAddr ||
413                    (inst->SrcReg[j].File == PROGRAM_TEMPORARY &&
414                    inst->SrcReg[j].Index == index &&
415                    (get_src_arg_mask(inst,j,NO_MASK) & mask)))
416                   return READ;
417             }
418             if (_mesa_num_inst_dst_regs(inst->Opcode) == 1 &&
419                 inst->DstReg.File == PROGRAM_TEMPORARY &&
420                 inst->DstReg.Index == index) {
421                mask &= ~inst->DstReg.WriteMask;
422                if (mask == 0)
423                   return WRITE;
424             }
425          }
426       }
427    }
428    return END;
429 }
430
431
432 /**
433  * Is the given instruction opcode a flow-control opcode?
434  * XXX maybe move this into prog_instruction.[ch]
435  */
436 static GLboolean
437 _mesa_is_flow_control_opcode(enum prog_opcode opcode)
438 {
439    switch (opcode) {
440    case OPCODE_BGNLOOP:
441    case OPCODE_BGNSUB:
442    case OPCODE_BRA:
443    case OPCODE_CAL:
444    case OPCODE_CONT:
445    case OPCODE_IF:
446    case OPCODE_ELSE:
447    case OPCODE_END:
448    case OPCODE_ENDIF:
449    case OPCODE_ENDLOOP:
450    case OPCODE_ENDSUB:
451    case OPCODE_RET:
452       return GL_TRUE;
453    default:
454       return GL_FALSE;
455    }
456 }
457
458
459 /**
460  * Test if the given instruction is a simple MOV (no conditional updating,
461  * not relative addressing, no negation/abs, etc).
462  */
463 static GLboolean
464 can_downward_mov_be_modifed(const struct prog_instruction *mov)
465 {
466    return
467       mov->Opcode == OPCODE_MOV &&
468       mov->CondUpdate == GL_FALSE &&
469       mov->SrcReg[0].RelAddr == 0 &&
470       mov->SrcReg[0].Negate == 0 &&
471       mov->SrcReg[0].Abs == 0 &&
472       mov->SrcReg[0].HasIndex2 == 0 &&
473       mov->SrcReg[0].RelAddr2 == 0 &&
474       mov->DstReg.RelAddr == 0 &&
475       mov->DstReg.CondMask == COND_TR &&
476       mov->SaturateMode == SATURATE_OFF;
477 }
478
479
480 static GLboolean
481 can_upward_mov_be_modifed(const struct prog_instruction *mov)
482 {
483    return
484       can_downward_mov_be_modifed(mov) &&
485       mov->DstReg.File == PROGRAM_TEMPORARY;
486 }
487
488
489 /**
490  * Try to remove use of extraneous MOV instructions, to free them up for dead
491  * code removal.
492  */
493 static void
494 _mesa_remove_extra_move_use(struct gl_program *prog)
495 {
496    GLuint i, j;
497
498    if (dbg) {
499       printf("Optimize: Begin remove extra move use\n");
500       _mesa_print_program(prog);
501    }
502
503    /*
504     * Look for sequences such as this:
505     *    MOV tmpX, arg0;
506     *    ...
507     *    FOO tmpY, tmpX, arg1;
508     * and convert into:
509     *    MOV tmpX, arg0;
510     *    ...
511     *    FOO tmpY, arg0, arg1;
512     */
513
514    for (i = 0; i + 1 < prog->NumInstructions; i++) {
515       const struct prog_instruction *mov = prog->Instructions + i;
516       GLuint dst_mask, src_mask;
517       if (can_upward_mov_be_modifed(mov) == GL_FALSE)
518          continue;
519
520       /* Scanning the code, we maintain the components which are still active in
521        * these two masks
522        */
523       dst_mask = mov->DstReg.WriteMask;
524       src_mask = get_src_arg_mask(mov, 0, NO_MASK);
525
526       /* Walk through remaining instructions until the or src reg gets
527        * rewritten or we get into some flow-control, eliminating the use of
528        * this MOV.
529        */
530       for (j = i + 1; j < prog->NumInstructions; j++) {
531          struct prog_instruction *inst2 = prog->Instructions + j;
532          GLuint arg;
533
534          if (_mesa_is_flow_control_opcode(inst2->Opcode))
535              break;
536
537          /* First rewrite this instruction's args if appropriate. */
538          for (arg = 0; arg < _mesa_num_inst_src_regs(inst2->Opcode); arg++) {
539             GLuint comp, read_mask;
540
541             if (inst2->SrcReg[arg].File != mov->DstReg.File ||
542                 inst2->SrcReg[arg].Index != mov->DstReg.Index ||
543                 inst2->SrcReg[arg].RelAddr ||
544                 inst2->SrcReg[arg].Abs)
545                continue;
546             read_mask = get_src_arg_mask(inst2, arg, NO_MASK);
547
548             /* Adjust the swizzles of inst2 to point at MOV's source if ALL the
549              * components read still come from the mov instructions
550              */
551             if (is_swizzle_regular(inst2->SrcReg[arg].Swizzle) &&
552                (read_mask & dst_mask) == read_mask) {
553                for (comp = 0; comp < 4; comp++) {
554                   const GLuint inst2_swz =
555                      GET_SWZ(inst2->SrcReg[arg].Swizzle, comp);
556                   const GLuint s = GET_SWZ(mov->SrcReg[0].Swizzle, inst2_swz);
557                   inst2->SrcReg[arg].Swizzle &= ~(7 << (3 * comp));
558                   inst2->SrcReg[arg].Swizzle |= s << (3 * comp);
559                   inst2->SrcReg[arg].Negate ^= (((mov->SrcReg[0].Negate >>
560                                                   inst2_swz) & 0x1) << comp);
561                }
562                inst2->SrcReg[arg].File = mov->SrcReg[0].File;
563                inst2->SrcReg[arg].Index = mov->SrcReg[0].Index;
564             }
565          }
566
567          /* The source of MOV is written. This potentially deactivates some
568           * components from the src and dst of the MOV instruction
569           */
570          if (inst2->DstReg.File == mov->DstReg.File &&
571              (inst2->DstReg.RelAddr ||
572               inst2->DstReg.Index == mov->DstReg.Index)) {
573             dst_mask &= ~inst2->DstReg.WriteMask;
574             src_mask = get_src_arg_mask(mov, 0, dst_mask);
575          }
576
577          /* Idem when the destination of mov is written */
578          if (inst2->DstReg.File == mov->SrcReg[0].File &&
579              (inst2->DstReg.RelAddr ||
580               inst2->DstReg.Index == mov->SrcReg[0].Index)) {
581             src_mask &= ~inst2->DstReg.WriteMask;
582             dst_mask &= get_dst_mask_for_mov(mov, src_mask);
583          }
584          if (dst_mask == 0)
585             break;
586       }
587    }
588
589    if (dbg) {
590       printf("Optimize: End remove extra move use.\n");
591       /*_mesa_print_program(prog);*/
592    }
593 }
594
595
596 /**
597  * Complements dead_code_global. Try to remove code in block of code by
598  * carefully monitoring the swizzles. Both functions should be merged into one
599  * with a proper control flow graph
600  */
601 static GLboolean
602 _mesa_remove_dead_code_local(struct gl_program *prog)
603 {
604    GLboolean *removeInst;
605    GLuint i, arg, rem = 0;
606
607    removeInst = (GLboolean *)
608       calloc(1, prog->NumInstructions * sizeof(GLboolean));
609
610    for (i = 0; i < prog->NumInstructions; i++) {
611       const struct prog_instruction *inst = prog->Instructions + i;
612       const GLuint index = inst->DstReg.Index;
613       const GLuint mask = inst->DstReg.WriteMask;
614       enum inst_use use;
615
616       /* We must deactivate the pass as soon as some indirection is used */
617       if (inst->DstReg.RelAddr)
618          goto done;
619       for (arg = 0; arg < _mesa_num_inst_src_regs(inst->Opcode); arg++)
620          if (inst->SrcReg[arg].RelAddr)
621             goto done;
622
623       if (_mesa_is_flow_control_opcode(inst->Opcode) ||
624           _mesa_num_inst_dst_regs(inst->Opcode) == 0 ||
625           inst->DstReg.File != PROGRAM_TEMPORARY ||
626           inst->DstReg.RelAddr)
627          continue;
628
629       use = find_next_use(prog, i+1, index, mask);
630       if (use == WRITE || use == END)
631          removeInst[i] = GL_TRUE;
632    }
633
634    rem = remove_instructions(prog, removeInst);
635
636 done:
637    free(removeInst);
638    return rem != 0;
639 }
640
641
642 /**
643  * Try to inject the destination of mov as the destination of inst and recompute
644  * the swizzles operators for the sources of inst if required. Return GL_TRUE
645  * of the substitution was possible, GL_FALSE otherwise
646  */
647 static GLboolean
648 _mesa_merge_mov_into_inst(struct prog_instruction *inst,
649                           const struct prog_instruction *mov)
650 {
651    /* Indirection table which associates destination and source components for
652     * the mov instruction
653     */
654    const GLuint mask = get_src_arg_mask(mov, 0, NO_MASK);
655
656    /* Some components are not written by inst. We cannot remove the mov */
657    if (mask != (inst->DstReg.WriteMask & mask))
658       return GL_FALSE;
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 = (GLboolean *)
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.CondSrc == 0 && 
793                 prevInst->DstReg.CondMask == COND_TR) {
794
795                const GLuint dst_mask = prevInst->DstReg.WriteMask;
796                enum inst_use next_use = find_next_use(prog, i+1, id, dst_mask);
797
798                if (next_use == WRITE || next_use == END) {
799                   /* OK, we can safely remove this MOV instruction.
800                    * Transform:
801                    *   prevI: FOO tempIndex, x, y;
802                    *       i: MOV z, tempIndex;
803                    * Into:
804                    *   prevI: FOO z, x, y;
805                    */
806                   if (_mesa_merge_mov_into_inst(prevInst, mov)) {
807                      removeInst[i] = GL_TRUE;
808                      if (dbg) {
809                         printf("Remove MOV at %u\n", i);
810                         printf("new prev inst %u: ", prevI);
811                         _mesa_print_instruction(prevInst);
812                      }
813                   }
814                }
815             }
816          }
817          break;
818       default:
819          ; /* nothing */
820       }
821    }
822
823    /* now remove the instructions which aren't needed */
824    rem = remove_instructions(prog, removeInst);
825
826    free(removeInst);
827
828    if (dbg) {
829       printf("Optimize: End remove extra moves.  %u instructions removed\n", rem);
830       /*_mesa_print_program(prog);*/
831    }
832
833    return rem != 0;
834 }
835
836
837 /** A live register interval */
838 struct interval
839 {
840    GLuint Reg;         /** The temporary register index */
841    GLuint Start, End;  /** Start/end instruction numbers */
842 };
843
844
845 /** A list of register intervals */
846 struct interval_list
847 {
848    GLuint Num;
849    struct interval Intervals[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
850 };
851
852
853 static void
854 append_interval(struct interval_list *list, const struct interval *inv)
855 {
856    list->Intervals[list->Num++] = *inv;
857 }
858
859
860 /** Insert interval inv into list, sorted by interval end */
861 static void
862 insert_interval_by_end(struct interval_list *list, const struct interval *inv)
863 {
864    /* XXX we could do a binary search insertion here since list is sorted */
865    GLint i = list->Num - 1;
866    while (i >= 0 && list->Intervals[i].End > inv->End) {
867       list->Intervals[i + 1] = list->Intervals[i];
868       i--;
869    }
870    list->Intervals[i + 1] = *inv;
871    list->Num++;
872
873 #ifdef DEBUG
874    {
875       GLuint i;
876       for (i = 0; i + 1 < list->Num; i++) {
877          ASSERT(list->Intervals[i].End <= list->Intervals[i + 1].End);
878       }
879    }
880 #endif
881 }
882
883
884 /** Remove the given interval from the interval list */
885 static void
886 remove_interval(struct interval_list *list, const struct interval *inv)
887 {
888    /* XXX we could binary search since list is sorted */
889    GLuint k;
890    for (k = 0; k < list->Num; k++) {
891       if (list->Intervals[k].Reg == inv->Reg) {
892          /* found, remove it */
893          ASSERT(list->Intervals[k].Start == inv->Start);
894          ASSERT(list->Intervals[k].End == inv->End);
895          while (k < list->Num - 1) {
896             list->Intervals[k] = list->Intervals[k + 1];
897             k++;
898          }
899          list->Num--;
900          return;
901       }
902    }
903 }
904
905
906 /** called by qsort() */
907 static int
908 compare_start(const void *a, const void *b)
909 {
910    const struct interval *ia = (const struct interval *) a;
911    const struct interval *ib = (const struct interval *) b;
912    if (ia->Start < ib->Start)
913       return -1;
914    else if (ia->Start > ib->Start)
915       return +1;
916    else
917       return 0;
918 }
919
920
921 /** sort the interval list according to interval starts */
922 static void
923 sort_interval_list_by_start(struct interval_list *list)
924 {
925    qsort(list->Intervals, list->Num, sizeof(struct interval), compare_start);
926 #ifdef DEBUG
927    {
928       GLuint i;
929       for (i = 0; i + 1 < list->Num; i++) {
930          ASSERT(list->Intervals[i].Start <= list->Intervals[i + 1].Start);
931       }
932    }
933 #endif
934 }
935
936 struct loop_info
937 {
938    GLuint Start, End;  /**< Start, end instructions of loop */
939 };
940
941 /**
942  * Update the intermediate interval info for register 'index' and
943  * instruction 'ic'.
944  */
945 static void
946 update_interval(GLint intBegin[], GLint intEnd[],
947                 struct loop_info *loopStack, GLuint loopStackDepth,
948                 GLuint index, GLuint ic)
949 {
950    int i;
951    GLuint begin = ic;
952    GLuint end = ic;
953
954    /* If the register is used in a loop, extend its lifetime through the end
955     * of the outermost loop that doesn't contain its definition.
956     */
957    for (i = 0; i < loopStackDepth; i++) {
958       if (intBegin[index] < loopStack[i].Start) {
959          end = loopStack[i].End;
960          break;
961       }
962    }
963
964    /* Variables that are live at the end of a loop will also be live at the
965     * beginning, so an instruction inside of a loop should have its live
966     * interval begin at the start of the outermost loop.
967     */
968    if (loopStackDepth > 0 && ic > loopStack[0].Start && ic < loopStack[0].End) {
969       begin = loopStack[0].Start;
970    }
971
972    ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS);
973    if (intBegin[index] == -1) {
974       ASSERT(intEnd[index] == -1);
975       intBegin[index] = begin;
976       intEnd[index] = end;
977    }
978    else {
979       intEnd[index] = end;
980    }
981 }
982
983
984 /**
985  * Find first/last instruction that references each temporary register.
986  */
987 GLboolean
988 _mesa_find_temp_intervals(const struct prog_instruction *instructions,
989                           GLuint numInstructions,
990                           GLint intBegin[REG_ALLOCATE_MAX_PROGRAM_TEMPS],
991                           GLint intEnd[REG_ALLOCATE_MAX_PROGRAM_TEMPS])
992 {
993    struct loop_info loopStack[MAX_LOOP_NESTING];
994    GLuint loopStackDepth = 0;
995    GLuint i;
996
997    for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++){
998       intBegin[i] = intEnd[i] = -1;
999    }
1000
1001    /* Scan instructions looking for temporary registers */
1002    for (i = 0; i < numInstructions; i++) {
1003       const struct prog_instruction *inst = instructions + i;
1004       if (inst->Opcode == OPCODE_BGNLOOP) {
1005          loopStack[loopStackDepth].Start = i;
1006          loopStack[loopStackDepth].End = inst->BranchTarget;
1007          loopStackDepth++;
1008       }
1009       else if (inst->Opcode == OPCODE_ENDLOOP) {
1010          loopStackDepth--;
1011       }
1012       else if (inst->Opcode == OPCODE_CAL) {
1013          return GL_FALSE;
1014       }
1015       else {
1016          const GLuint numSrc = 3;/*_mesa_num_inst_src_regs(inst->Opcode);*/
1017          GLuint j;
1018          for (j = 0; j < numSrc; j++) {
1019             if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) {
1020                const GLuint index = inst->SrcReg[j].Index;
1021                if (inst->SrcReg[j].RelAddr)
1022                   return GL_FALSE;
1023                update_interval(intBegin, intEnd, loopStack, loopStackDepth,
1024                                index, i);
1025             }
1026          }
1027          if (inst->DstReg.File == PROGRAM_TEMPORARY) {
1028             const GLuint index = inst->DstReg.Index;
1029             if (inst->DstReg.RelAddr)
1030                return GL_FALSE;
1031             update_interval(intBegin, intEnd, loopStack, loopStackDepth,
1032                             index, i);
1033          }
1034       }
1035    }
1036
1037    return GL_TRUE;
1038 }
1039
1040
1041 /**
1042  * Find the live intervals for each temporary register in the program.
1043  * For register R, the interval [A,B] indicates that R is referenced
1044  * from instruction A through instruction B.
1045  * Special consideration is needed for loops and subroutines.
1046  * \return GL_TRUE if success, GL_FALSE if we cannot proceed for some reason
1047  */
1048 static GLboolean
1049 find_live_intervals(struct gl_program *prog,
1050                     struct interval_list *liveIntervals)
1051 {
1052    GLint intBegin[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
1053    GLint intEnd[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
1054    GLuint i;
1055
1056    /*
1057     * Note: we'll return GL_FALSE below if we find relative indexing
1058     * into the TEMP register file.  We can't handle that yet.
1059     * We also give up on subroutines for now.
1060     */
1061
1062    if (dbg) {
1063       printf("Optimize: Begin find intervals\n");
1064    }
1065
1066    /* build intermediate arrays */
1067    if (!_mesa_find_temp_intervals(prog->Instructions, prog->NumInstructions,
1068                                   intBegin, intEnd))
1069       return GL_FALSE;
1070
1071    /* Build live intervals list from intermediate arrays */
1072    liveIntervals->Num = 0;
1073    for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++) {
1074       if (intBegin[i] >= 0) {
1075          struct interval inv;
1076          inv.Reg = i;
1077          inv.Start = intBegin[i];
1078          inv.End = intEnd[i];
1079          append_interval(liveIntervals, &inv);
1080       }
1081    }
1082
1083    /* Sort the list according to interval starts */
1084    sort_interval_list_by_start(liveIntervals);
1085
1086    if (dbg) {
1087       /* print interval info */
1088       for (i = 0; i < liveIntervals->Num; i++) {
1089          const struct interval *inv = liveIntervals->Intervals + i;
1090          printf("Reg[%d] live [%d, %d]:",
1091                       inv->Reg, inv->Start, inv->End);
1092          if (1) {
1093             GLuint j;
1094             for (j = 0; j < inv->Start; j++)
1095                printf(" ");
1096             for (j = inv->Start; j <= inv->End; j++)
1097                printf("x");
1098          }
1099          printf("\n");
1100       }
1101    }
1102
1103    return GL_TRUE;
1104 }
1105
1106
1107 /** Scan the array of used register flags to find free entry */
1108 static GLint
1109 alloc_register(GLboolean usedRegs[REG_ALLOCATE_MAX_PROGRAM_TEMPS])
1110 {
1111    GLuint k;
1112    for (k = 0; k < REG_ALLOCATE_MAX_PROGRAM_TEMPS; k++) {
1113       if (!usedRegs[k]) {
1114          usedRegs[k] = GL_TRUE;
1115          return k;
1116       }
1117    }
1118    return -1;
1119 }
1120
1121
1122 /**
1123  * This function implements "Linear Scan Register Allocation" to reduce
1124  * the number of temporary registers used by the program.
1125  *
1126  * We compute the "live interval" for all temporary registers then
1127  * examine the overlap of the intervals to allocate new registers.
1128  * Basically, if two intervals do not overlap, they can use the same register.
1129  */
1130 static void
1131 _mesa_reallocate_registers(struct gl_program *prog)
1132 {
1133    struct interval_list liveIntervals;
1134    GLint registerMap[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
1135    GLboolean usedRegs[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
1136    GLuint i;
1137    GLint maxTemp = -1;
1138
1139    if (dbg) {
1140       printf("Optimize: Begin live-interval register reallocation\n");
1141       _mesa_print_program(prog);
1142    }
1143
1144    for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++){
1145       registerMap[i] = -1;
1146       usedRegs[i] = GL_FALSE;
1147    }
1148
1149    if (!find_live_intervals(prog, &liveIntervals)) {
1150       if (dbg)
1151          printf("Aborting register reallocation\n");
1152       return;
1153    }
1154
1155    {
1156       struct interval_list activeIntervals;
1157       activeIntervals.Num = 0;
1158
1159       /* loop over live intervals, allocating a new register for each */
1160       for (i = 0; i < liveIntervals.Num; i++) {
1161          const struct interval *live = liveIntervals.Intervals + i;
1162
1163          if (dbg)
1164             printf("Consider register %u\n", live->Reg);
1165
1166          /* Expire old intervals.  Intervals which have ended with respect
1167           * to the live interval can have their remapped registers freed.
1168           */
1169          {
1170             GLint j;
1171             for (j = 0; j < (GLint) activeIntervals.Num; j++) {
1172                const struct interval *inv = activeIntervals.Intervals + j;
1173                if (inv->End >= live->Start) {
1174                   /* Stop now.  Since the activeInterval list is sorted
1175                    * we know we don't have to go further.
1176                    */
1177                   break;
1178                }
1179                else {
1180                   /* Interval 'inv' has expired */
1181                   const GLint regNew = registerMap[inv->Reg];
1182                   ASSERT(regNew >= 0);
1183
1184                   if (dbg)
1185                      printf("  expire interval for reg %u\n", inv->Reg);
1186
1187                   /* remove interval j from active list */
1188                   remove_interval(&activeIntervals, inv);
1189                   j--;  /* counter-act j++ in for-loop above */
1190
1191                   /* return register regNew to the free pool */
1192                   if (dbg)
1193                      printf("  free reg %d\n", regNew);
1194                   ASSERT(usedRegs[regNew] == GL_TRUE);
1195                   usedRegs[regNew] = GL_FALSE;
1196                }
1197             }
1198          }
1199
1200          /* find a free register for this live interval */
1201          {
1202             const GLint k = alloc_register(usedRegs);
1203             if (k < 0) {
1204                /* out of registers, give up */
1205                return;
1206             }
1207             registerMap[live->Reg] = k;
1208             maxTemp = MAX2(maxTemp, k);
1209             if (dbg)
1210                printf("  remap register %u -> %d\n", live->Reg, k);
1211          }
1212
1213          /* Insert this live interval into the active list which is sorted
1214           * by increasing end points.
1215           */
1216          insert_interval_by_end(&activeIntervals, live);
1217       }
1218    }
1219
1220    if (maxTemp + 1 < (GLint) liveIntervals.Num) {
1221       /* OK, we've reduced the number of registers needed.
1222        * Scan the program and replace all the old temporary register
1223        * indexes with the new indexes.
1224        */
1225       replace_regs(prog, PROGRAM_TEMPORARY, registerMap);
1226
1227       prog->NumTemporaries = maxTemp + 1;
1228    }
1229
1230    if (dbg) {
1231       printf("Optimize: End live-interval register reallocation\n");
1232       printf("Num temp regs before: %u  after: %u\n",
1233                    liveIntervals.Num, maxTemp + 1);
1234       _mesa_print_program(prog);
1235    }
1236 }
1237
1238
1239 #if 0
1240 static void
1241 print_it(struct gl_context *ctx, struct gl_program *program, const char *txt) {
1242    fprintf(stderr, "%s (%u inst):\n", txt, program->NumInstructions);
1243    _mesa_print_program(program);
1244    _mesa_print_program_parameters(ctx, program);
1245    fprintf(stderr, "\n\n");
1246 }
1247 #endif
1248
1249 /**
1250  * This pass replaces CMP T0, T1 T2 T0 with MOV T0, T2 when the CMP
1251  * instruction is the first instruction to write to register T0.  The are
1252  * several lowering passes done in GLSL IR (e.g. branches and
1253  * relative addressing) that create a large number of conditional assignments
1254  * that ir_to_mesa converts to CMP instructions like the one mentioned above.
1255  *
1256  * Here is why this conversion is safe:
1257  * CMP T0, T1 T2 T0 can be expanded to:
1258  * if (T1 < 0.0)
1259  *      MOV T0, T2;
1260  * else
1261  *      MOV T0, T0;
1262  *
1263  * If (T1 < 0.0) evaluates to true then our replacement MOV T0, T2 is the same
1264  * as the original program.  If (T1 < 0.0) evaluates to false, executing
1265  * MOV T0, T0 will store a garbage value in T0 since T0 is uninitialized.
1266  * Therefore, it doesn't matter that we are replacing MOV T0, T0 with MOV T0, T2
1267  * because any instruction that was going to read from T0 after this was going
1268  * to read a garbage value anyway.
1269  */
1270 static void
1271 _mesa_simplify_cmp(struct gl_program * program)
1272 {
1273    GLuint tempWrites[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
1274    GLuint outputWrites[MAX_PROGRAM_OUTPUTS];
1275    GLuint i;
1276
1277    if (dbg) {
1278       printf("Optimize: Begin reads without writes\n");
1279       _mesa_print_program(program);
1280    }
1281
1282    for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++) {
1283       tempWrites[i] = 0;
1284    }
1285
1286    for (i = 0; i < MAX_PROGRAM_OUTPUTS; i++) {
1287       outputWrites[i] = 0;
1288    }
1289
1290    for (i = 0; i < program->NumInstructions; i++) {
1291       struct prog_instruction *inst = program->Instructions + i;
1292       GLuint prevWriteMask;
1293
1294       /* Give up if we encounter relative addressing or flow control. */
1295       if (_mesa_is_flow_control_opcode(inst->Opcode) || inst->DstReg.RelAddr) {
1296          return;
1297       }
1298
1299       if (inst->DstReg.File == PROGRAM_OUTPUT) {
1300          assert(inst->DstReg.Index < MAX_PROGRAM_OUTPUTS);
1301          prevWriteMask = outputWrites[inst->DstReg.Index];
1302          outputWrites[inst->DstReg.Index] |= inst->DstReg.WriteMask;
1303       } else if (inst->DstReg.File == PROGRAM_TEMPORARY) {
1304          assert(inst->DstReg.Index < REG_ALLOCATE_MAX_PROGRAM_TEMPS);
1305          prevWriteMask = tempWrites[inst->DstReg.Index];
1306          tempWrites[inst->DstReg.Index] |= inst->DstReg.WriteMask;
1307       } else {
1308          /* No other register type can be a destination register. */
1309          continue;
1310       }
1311
1312       /* For a CMP to be considered a conditional write, the destination
1313        * register and source register two must be the same. */
1314       if (inst->Opcode == OPCODE_CMP
1315           && !(inst->DstReg.WriteMask & prevWriteMask)
1316           && inst->SrcReg[2].File == inst->DstReg.File
1317           && inst->SrcReg[2].Index == inst->DstReg.Index
1318           && inst->DstReg.WriteMask == get_src_arg_mask(inst, 2, NO_MASK)) {
1319
1320          inst->Opcode = OPCODE_MOV;
1321          inst->SrcReg[0] = inst->SrcReg[1];
1322
1323          /* Unused operands are expected to have the file set to
1324           * PROGRAM_UNDEFINED.  This is how _mesa_init_instructions initializes
1325           * all of the sources.
1326           */
1327          inst->SrcReg[1].File = PROGRAM_UNDEFINED;
1328          inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
1329          inst->SrcReg[2].File = PROGRAM_UNDEFINED;
1330          inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
1331       }
1332    }
1333    if (dbg) {
1334       printf("Optimize: End reads without writes\n");
1335       _mesa_print_program(program);
1336    }
1337 }
1338
1339 /**
1340  * Apply optimizations to the given program to eliminate unnecessary
1341  * instructions, temp regs, etc.
1342  */
1343 void
1344 _mesa_optimize_program(struct gl_context *ctx, struct gl_program *program)
1345 {
1346    GLboolean any_change;
1347
1348    _mesa_simplify_cmp(program);
1349    /* Stop when no modifications were output */
1350    do {
1351       any_change = GL_FALSE;
1352       _mesa_remove_extra_move_use(program);
1353       if (_mesa_remove_dead_code_global(program))
1354          any_change = GL_TRUE;
1355       if (_mesa_remove_extra_moves(program))
1356          any_change = GL_TRUE;
1357       if (_mesa_remove_dead_code_local(program))
1358          any_change = GL_TRUE;
1359       _mesa_reallocate_registers(program);
1360    } while (any_change);
1361 }
1362