mesa: Remove prog_instruction.h field for never-supported NV_vertex_program3.
[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