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