2 * Copyright © 2017 Gert Wollny
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 #include "st_glsl_to_tgsi_temprename.h"
25 #include <tgsi/tgsi_info.h>
26 #include <tgsi/tgsi_strings.h>
27 #include <program/prog_instruction.h>
31 /* std::sort is significantly faster than qsort */
40 #include <program/prog_print.h>
41 #include <util/debug.h>
46 /* If <windows.h> is included this is defined and clashes with
47 * std::numeric_limits<>::max()
53 using std::numeric_limits
;
55 /* Without c++11 define the nullptr for forward-compatibility
56 * and better readibility */
57 #if __cplusplus < 201103L
62 /* Helper function to check whether we want to seen debugging output */
63 static inline bool is_debug_enabled ()
65 static int debug_enabled
= -1;
66 if (debug_enabled
< 0)
67 debug_enabled
= env_var_as_boolean("GLSL_TO_TGSI_RENAME_DEBUG", false);
68 return debug_enabled
> 0;
70 #define RENAME_DEBUG(X) if (is_debug_enabled()) do { X; } while (false);
72 #define RENAME_DEBUG(X)
77 enum prog_scope_type
{
78 outer_scope
, /* Outer program scope */
79 loop_body
, /* Inside a loop */
80 if_branch
, /* Inside if branch */
81 else_branch
, /* Inside else branch */
82 switch_body
, /* Inside switch statmenet */
83 switch_case_branch
, /* Inside switch case statmenet */
84 switch_default_branch
, /* Inside switch default statmenet */
90 prog_scope(prog_scope
*parent
, prog_scope_type type
, int id
,
91 int depth
, int begin
);
93 prog_scope_type
type() const;
94 prog_scope
*parent() const;
95 int nesting_depth() const;
99 int loop_break_line() const;
101 const prog_scope
*in_ifelse_scope() const;
102 const prog_scope
*in_switchcase_scope() const;
103 const prog_scope
*innermost_loop() const;
104 const prog_scope
*outermost_loop() const;
105 const prog_scope
*enclosing_conditional() const;
107 bool is_loop() const;
108 bool is_in_loop() const;
109 bool is_conditional() const;
110 bool is_conditional_in_loop() const;
112 bool break_is_for_switchcase() const;
113 bool contains_range_of(const prog_scope
& other
) const;
114 const st_src_reg
*switch_register() const;
116 void set_end(int end
);
117 void set_loop_break_line(int line
);
120 prog_scope_type scope_type
;
122 int scope_nesting_depth
;
126 prog_scope
*parent_scope
;
127 const st_src_reg
*switch_reg
;
130 /* Some storage class to encapsulate the prog_scope (de-)allocations */
131 class prog_scope_storage
{
133 prog_scope_storage(void *mem_ctx
, int n
);
134 ~prog_scope_storage();
135 prog_scope
* create(prog_scope
*p
, prog_scope_type type
, int id
,
136 int lvl
, int s_begin
);
143 class temp_comp_access
{
146 void record_read(int line
, prog_scope
*scope
);
147 void record_write(int line
, prog_scope
*scope
);
148 lifetime
get_required_lifetime();
150 void propagate_lifetime_to_dominant_write_scope();
152 prog_scope
*last_read_scope
;
153 prog_scope
*first_read_scope
;
154 prog_scope
*first_write_scope
;
159 bool keep_for_full_loop
;
165 void record_read(int line
, prog_scope
*scope
, int swizzle
);
166 void record_write(int line
, prog_scope
*scope
, int writemask
);
167 lifetime
get_required_lifetime();
169 void update_access_mask(int mask
);
171 temp_comp_access comp
[4];
173 bool needs_component_tracking
;
176 prog_scope_storage::prog_scope_storage(void *mc
, int n
):
180 storage
= ralloc_array(mem_ctx
, prog_scope
, n
);
183 prog_scope_storage::~prog_scope_storage()
185 ralloc_free(storage
);
189 prog_scope_storage::create(prog_scope
*p
, prog_scope_type type
, int id
,
190 int lvl
, int s_begin
)
192 storage
[current_slot
] = prog_scope(p
, type
, id
, lvl
, s_begin
);
193 return &storage
[current_slot
++];
196 prog_scope::prog_scope(prog_scope
*parent
, prog_scope_type type
, int id
,
197 int depth
, int scope_begin
):
200 scope_nesting_depth(depth
),
201 scope_begin(scope_begin
),
203 break_loop_line(numeric_limits
<int>::max()),
204 parent_scope(parent
),
209 prog_scope_type
prog_scope::type() const
214 prog_scope
*prog_scope::parent() const
219 int prog_scope::nesting_depth() const
221 return scope_nesting_depth
;
224 bool prog_scope::is_loop() const
226 return (scope_type
== loop_body
);
229 bool prog_scope::is_in_loop() const
231 if (scope_type
== loop_body
)
235 return parent_scope
->is_in_loop();
240 bool prog_scope::is_conditional_in_loop() const
242 return is_conditional() && is_in_loop();
245 const prog_scope
*prog_scope::innermost_loop() const
247 if (scope_type
== loop_body
)
251 return parent_scope
->innermost_loop();
256 const prog_scope
*prog_scope::outermost_loop() const
258 const prog_scope
*loop
= nullptr;
259 const prog_scope
*p
= this;
262 if (p
->type() == loop_body
)
270 const prog_scope
*prog_scope::enclosing_conditional() const
272 if (is_conditional())
276 return parent_scope
->enclosing_conditional();
281 bool prog_scope::contains_range_of(const prog_scope
& other
) const
283 return (begin() <= other
.begin()) && (end() >= other
.end());
286 bool prog_scope::is_conditional() const
288 return scope_type
== if_branch
||
289 scope_type
== else_branch
||
290 scope_type
== switch_case_branch
||
291 scope_type
== switch_default_branch
;
294 const prog_scope
*prog_scope::in_ifelse_scope() const
296 if (scope_type
== if_branch
||
297 scope_type
== else_branch
)
301 return parent_scope
->in_ifelse_scope();
306 const st_src_reg
*prog_scope::switch_register() const
311 const prog_scope
*prog_scope::in_switchcase_scope() const
313 if (scope_type
== switch_case_branch
||
314 scope_type
== switch_default_branch
)
318 return parent_scope
->in_switchcase_scope();
323 bool prog_scope::break_is_for_switchcase() const
325 if (scope_type
== loop_body
)
328 if (scope_type
== switch_case_branch
||
329 scope_type
== switch_default_branch
||
330 scope_type
== switch_body
)
334 return parent_scope
->break_is_for_switchcase();
339 int prog_scope::id() const
344 int prog_scope::begin() const
349 int prog_scope::end() const
354 void prog_scope::set_end(int end
)
360 void prog_scope::set_loop_break_line(int line
)
362 if (scope_type
== loop_body
) {
363 break_loop_line
= MIN2(break_loop_line
, line
);
366 parent()->set_loop_break_line(line
);
370 int prog_scope::loop_break_line() const
372 return break_loop_line
;
375 temp_access::temp_access():
377 needs_component_tracking(false)
381 void temp_access::update_access_mask(int mask
)
383 if (access_mask
&& access_mask
!= mask
)
384 needs_component_tracking
= true;
388 void temp_access::record_write(int line
, prog_scope
*scope
, int writemask
)
390 update_access_mask(writemask
);
392 if (writemask
& WRITEMASK_X
)
393 comp
[0].record_write(line
, scope
);
394 if (writemask
& WRITEMASK_Y
)
395 comp
[1].record_write(line
, scope
);
396 if (writemask
& WRITEMASK_Z
)
397 comp
[2].record_write(line
, scope
);
398 if (writemask
& WRITEMASK_W
)
399 comp
[3].record_write(line
, scope
);
402 void temp_access::record_read(int line
, prog_scope
*scope
, int swizzle
)
405 for (int idx
= 0; idx
< 4; ++idx
) {
406 int swz
= GET_SWZ(swizzle
, idx
);
407 readmask
|= (1 << swz
) & 0xF;
409 update_access_mask(readmask
);
411 if (readmask
& WRITEMASK_X
)
412 comp
[0].record_read(line
, scope
);
413 if (readmask
& WRITEMASK_Y
)
414 comp
[1].record_read(line
, scope
);
415 if (readmask
& WRITEMASK_Z
)
416 comp
[2].record_read(line
, scope
);
417 if (readmask
& WRITEMASK_W
)
418 comp
[3].record_read(line
, scope
);
421 inline static lifetime
make_lifetime(int b
, int e
)
429 lifetime
temp_access::get_required_lifetime()
431 lifetime result
= make_lifetime(-1, -1);
433 unsigned mask
= access_mask
;
435 unsigned chan
= u_bit_scan(&mask
);
436 lifetime lt
= comp
[chan
].get_required_lifetime();
439 if ((result
.begin
< 0) || (result
.begin
> lt
.begin
))
440 result
.begin
= lt
.begin
;
443 if (lt
.end
> result
.end
)
446 if (!needs_component_tracking
)
452 temp_comp_access::temp_comp_access():
453 last_read_scope(nullptr),
454 first_read_scope(nullptr),
455 first_write_scope(nullptr),
459 first_read(numeric_limits
<int>::max())
463 void temp_comp_access::record_read(int line
, prog_scope
*scope
)
465 last_read_scope
= scope
;
468 if (first_read
> line
) {
470 first_read_scope
= scope
;
474 void temp_comp_access::record_write(int line
, prog_scope
*scope
)
478 if (first_write
< 0) {
480 first_write_scope
= scope
;
484 void temp_comp_access::propagate_lifetime_to_dominant_write_scope()
486 first_write
= first_write_scope
->begin();
487 int lr
= first_write_scope
->end();
493 lifetime
temp_comp_access::get_required_lifetime()
495 bool keep_for_full_loop
= false;
497 /* This register component is not used at all, or only read,
498 * mark it as unused and ignore it when renaming.
499 * glsl_to_tgsi_visitor::renumber_registers will take care of
500 * eliminating registers that are not written to.
503 return make_lifetime(-1, -1);
505 assert(first_write_scope
);
507 /* Only written to, just make sure the register component is not
508 * reused in the range it is used to write to
510 if (!last_read_scope
)
511 return make_lifetime(first_write
, last_write
+ 1);
513 const prog_scope
*enclosing_scope_first_read
= first_read_scope
;
514 const prog_scope
*enclosing_scope_first_write
= first_write_scope
;
516 /* We read before writing in a loop
517 * hence the value must survive the loops
519 if ((first_read
<= first_write
) &&
520 first_read_scope
->is_in_loop()) {
521 keep_for_full_loop
= true;
522 enclosing_scope_first_read
= first_read_scope
->outermost_loop();
525 /* A conditional write within a nested loop must survive
526 * the outermost loop, but only if it is read outside
527 * the condition scope where we write.
529 const prog_scope
*conditional
= enclosing_scope_first_write
->enclosing_conditional();
530 if (conditional
&& conditional
->is_in_loop() &&
531 !conditional
->contains_range_of(*last_read_scope
)) {
532 keep_for_full_loop
= true;
533 enclosing_scope_first_write
= conditional
->outermost_loop();
536 /* Evaluate the scope that is shared by all: required first write scope,
537 * required first read before write scope, and last read scope.
539 const prog_scope
*enclosing_scope
= enclosing_scope_first_read
;
540 if (enclosing_scope_first_write
->contains_range_of(*enclosing_scope
))
541 enclosing_scope
= enclosing_scope_first_write
;
543 if (last_read_scope
->contains_range_of(*enclosing_scope
))
544 enclosing_scope
= last_read_scope
;
546 while (!enclosing_scope
->contains_range_of(*enclosing_scope_first_write
) ||
547 !enclosing_scope
->contains_range_of(*last_read_scope
)) {
548 enclosing_scope
= enclosing_scope
->parent();
549 assert(enclosing_scope
);
552 /* Propagate the last read scope to the target scope */
553 while (enclosing_scope
->nesting_depth() < last_read_scope
->nesting_depth()) {
554 /* If the read is in a loop and we have to move up the scope we need to
555 * extend the life time to the end of this current loop because at this
556 * point we don't know whether the component was written before
557 * un-conditionally in the same loop.
559 if (last_read_scope
->is_loop())
560 last_read
= last_read_scope
->end();
562 last_read_scope
= last_read_scope
->parent();
565 /* If the variable has to be kept for the whole loop, and we
566 * are currently in a loop, then propagate the life time.
568 if (keep_for_full_loop
&& first_write_scope
->is_loop())
569 propagate_lifetime_to_dominant_write_scope();
571 /* Propagate the first_dominant_write scope to the target scope */
572 while (enclosing_scope
->nesting_depth() < first_write_scope
->nesting_depth()) {
573 /* Propagate lifetime if there was a break in a loop and the write was
574 * after the break inside that loop. Note, that this is only needed if
575 * we move up in the scopes.
577 if (first_write_scope
->loop_break_line() < first_write
) {
578 keep_for_full_loop
= true;
579 propagate_lifetime_to_dominant_write_scope();
582 first_write_scope
= first_write_scope
->parent();
584 /* Propagte lifetime if we are now in a loop */
585 if (keep_for_full_loop
&& first_write_scope
->is_loop())
586 propagate_lifetime_to_dominant_write_scope();
589 /* The last write past the last read is dead code, but we have to
590 * ensure that the component is not reused too early, hence extend the
591 * lifetime past the last write.
593 if (last_write
>= last_read
)
594 last_read
= last_write
+ 1;
596 /* Here we are at the same scope, all is resolved */
597 return make_lifetime(first_write
, last_read
);
600 /* Helper class for sorting and searching the registers based
602 class access_record
{
609 bool operator < (const access_record
& rhs
) const {
610 return begin
< rhs
.begin
;
617 /* Function used for debugging. */
618 static void dump_instruction(int line
, prog_scope
*scope
,
619 const glsl_to_tgsi_instruction
& inst
);
622 /* Scan the program and estimate the required register life times.
623 * The array lifetimes must be pre-allocated
626 get_temp_registers_required_lifetimes(void *mem_ctx
, exec_list
*instructions
,
627 int ntemps
, struct lifetime
*lifetimes
)
633 bool is_at_end
= false;
636 /* Count scopes to allocate the needed space without the need for
639 foreach_in_list(glsl_to_tgsi_instruction
, inst
, instructions
) {
640 if (inst
->op
== TGSI_OPCODE_BGNLOOP
||
641 inst
->op
== TGSI_OPCODE_SWITCH
||
642 inst
->op
== TGSI_OPCODE_CASE
||
643 inst
->op
== TGSI_OPCODE_IF
||
644 inst
->op
== TGSI_OPCODE_UIF
||
645 inst
->op
== TGSI_OPCODE_ELSE
||
646 inst
->op
== TGSI_OPCODE_DEFAULT
)
650 prog_scope_storage
scopes(mem_ctx
, n_scopes
);
651 temp_access
*acc
= new temp_access
[ntemps
];
653 prog_scope
*cur_scope
= scopes
.create(nullptr, outer_scope
, 0, 0, line
);
655 RENAME_DEBUG(cerr
<< "========= Begin shader ============\n");
657 foreach_in_list(glsl_to_tgsi_instruction
, inst
, instructions
) {
659 assert(!"GLSL_TO_TGSI: shader has instructions past end marker");
663 RENAME_DEBUG(dump_instruction(line
, cur_scope
, *inst
));
666 case TGSI_OPCODE_BGNLOOP
: {
667 cur_scope
= scopes
.create(cur_scope
, loop_body
, loop_id
++,
668 cur_scope
->nesting_depth() + 1, line
);
671 case TGSI_OPCODE_ENDLOOP
: {
672 cur_scope
->set_end(line
);
673 cur_scope
= cur_scope
->parent();
678 case TGSI_OPCODE_UIF
: {
679 assert(num_inst_src_regs(inst
) == 1);
680 const st_src_reg
& src
= inst
->src
[0];
681 if (src
.file
== PROGRAM_TEMPORARY
)
682 acc
[src
.index
].record_read(line
, cur_scope
, src
.swizzle
);
683 cur_scope
= scopes
.create(cur_scope
, if_branch
, if_id
++,
684 cur_scope
->nesting_depth() + 1, line
+ 1);
687 case TGSI_OPCODE_ELSE
: {
688 assert(cur_scope
->type() == if_branch
);
689 cur_scope
->set_end(line
- 1);
690 cur_scope
= scopes
.create(cur_scope
->parent(), else_branch
,
691 cur_scope
->id(), cur_scope
->nesting_depth(),
695 case TGSI_OPCODE_END
: {
696 cur_scope
->set_end(line
);
700 case TGSI_OPCODE_ENDIF
: {
701 cur_scope
->set_end(line
- 1);
702 cur_scope
= cur_scope
->parent();
706 case TGSI_OPCODE_SWITCH
: {
707 assert(num_inst_src_regs(inst
) == 1);
708 const st_src_reg
& src
= inst
->src
[0];
709 prog_scope
*scope
= scopes
.create(cur_scope
, switch_body
, switch_id
++,
710 cur_scope
->nesting_depth() + 1, line
);
711 /* We record the read only for the SWITCH statement itself, like it
712 * is used by the only consumer of TGSI_OPCODE_SWITCH in tgsi_exec.c.
714 if (src
.file
== PROGRAM_TEMPORARY
)
715 acc
[src
.index
].record_read(line
, cur_scope
, src
.swizzle
);
719 case TGSI_OPCODE_ENDSWITCH
: {
720 cur_scope
->set_end(line
- 1);
721 /* Remove the case level, it might not have been
722 * closed with a break.
724 if (cur_scope
->type() != switch_body
)
725 cur_scope
= cur_scope
->parent();
727 cur_scope
= cur_scope
->parent();
731 case TGSI_OPCODE_CASE
: {
732 /* Take care of tracking the registers. */
733 prog_scope
*switch_scope
= cur_scope
->type() == switch_body
?
734 cur_scope
: cur_scope
->parent();
736 assert(num_inst_src_regs(inst
) == 1);
737 const st_src_reg
& src
= inst
->src
[0];
738 if (src
.file
== PROGRAM_TEMPORARY
)
739 acc
[src
.index
].record_read(line
, switch_scope
, src
.swizzle
);
741 /* Fall through to allocate the scope. */
743 case TGSI_OPCODE_DEFAULT
: {
744 prog_scope_type t
= inst
->op
== TGSI_OPCODE_CASE
? switch_case_branch
745 : switch_default_branch
;
746 prog_scope
*switch_scope
= (cur_scope
->type() == switch_body
) ?
747 cur_scope
: cur_scope
->parent();
748 assert(switch_scope
->type() == switch_body
);
749 prog_scope
*scope
= scopes
.create(switch_scope
, t
,
751 switch_scope
->nesting_depth() + 1,
753 /* Previous case falls through, so scope was not yet closed. */
754 if ((cur_scope
!= switch_scope
) && (cur_scope
->end() == -1))
755 cur_scope
->set_end(line
- 1);
759 case TGSI_OPCODE_BRK
: {
760 if (cur_scope
->break_is_for_switchcase()) {
761 cur_scope
->set_end(line
- 1);
763 cur_scope
->set_loop_break_line(line
);
767 case TGSI_OPCODE_CAL
:
768 case TGSI_OPCODE_RET
:
769 /* These opcodes are not supported and if a subroutine would
770 * be called in a shader, then the lifetime tracking would have
771 * to follow that call to see which registers are used there.
772 * Since this is not done, we have to bail out here and signal
773 * that no register merge will take place.
777 for (unsigned j
= 0; j
< num_inst_src_regs(inst
); j
++) {
778 const st_src_reg
& src
= inst
->src
[j
];
779 if (src
.file
== PROGRAM_TEMPORARY
)
780 acc
[src
.index
].record_read(line
, cur_scope
, src
.swizzle
);
782 for (unsigned j
= 0; j
< inst
->tex_offset_num_offset
; j
++) {
783 const st_src_reg
& src
= inst
->tex_offsets
[j
];
784 if (src
.file
== PROGRAM_TEMPORARY
)
785 acc
[src
.index
].record_read(line
, cur_scope
, src
.swizzle
);
787 for (unsigned j
= 0; j
< num_inst_dst_regs(inst
); j
++) {
788 const st_dst_reg
& dst
= inst
->dst
[j
];
789 if (dst
.file
== PROGRAM_TEMPORARY
)
790 acc
[dst
.index
].record_write(line
, cur_scope
, dst
.writemask
);
797 RENAME_DEBUG(cerr
<< "==================================\n\n");
799 /* Make sure last scope is closed, even though no
800 * TGSI_OPCODE_END was given.
802 if (cur_scope
->end() < 0)
803 cur_scope
->set_end(line
- 1);
805 RENAME_DEBUG(cerr
<< "========= lifetimes ==============\n");
806 for(int i
= 0; i
< ntemps
; ++i
) {
807 RENAME_DEBUG(cerr
<< setw(4) << i
);
808 lifetimes
[i
] = acc
[i
].get_required_lifetime();
809 RENAME_DEBUG(cerr
<< ": [" << lifetimes
[i
].begin
<< ", "
810 << lifetimes
[i
].end
<< "]\n");
812 RENAME_DEBUG(cerr
<< "==================================\n\n");
818 /* Find the next register between [start, end) that has a life time starting
819 * at or after bound by using a binary search.
820 * start points at the beginning of the search range,
821 * end points at the element past the end of the search range, and
822 * the array comprising [start, end) must be sorted in ascending order.
824 static access_record
*
825 find_next_rename(access_record
* start
, access_record
* end
, int bound
)
827 int delta
= (end
- start
);
830 int half
= delta
>> 1;
831 access_record
* middle
= start
+ half
;
833 if (bound
<= middle
->begin
) {
846 static int access_record_compare (const void *a
, const void *b
) {
847 const access_record
*aa
= static_cast<const access_record
*>(a
);
848 const access_record
*bb
= static_cast<const access_record
*>(b
);
849 return aa
->begin
< bb
->begin
? -1 : (aa
->begin
> bb
->begin
? 1 : 0);
853 /* This functions evaluates the register merges by using a binary
854 * search to find suitable merge candidates. */
855 void get_temp_registers_remapping(void *mem_ctx
, int ntemps
,
856 const struct lifetime
* lifetimes
,
857 struct rename_reg_pair
*result
)
859 access_record
*reg_access
= ralloc_array(mem_ctx
, access_record
, ntemps
);
862 for (int i
= 0; i
< ntemps
; ++i
) {
863 if (lifetimes
[i
].begin
>= 0) {
864 reg_access
[used_temps
].begin
= lifetimes
[i
].begin
;
865 reg_access
[used_temps
].end
= lifetimes
[i
].end
;
866 reg_access
[used_temps
].reg
= i
;
867 reg_access
[used_temps
].erase
= false;
873 std::sort(reg_access
, reg_access
+ used_temps
);
875 std::qsort(reg_access
, used_temps
, sizeof(access_record
), access_record_compare
);
878 access_record
*trgt
= reg_access
;
879 access_record
*reg_access_end
= reg_access
+ used_temps
;
880 access_record
*first_erase
= reg_access_end
;
881 access_record
*search_start
= trgt
+ 1;
883 while (trgt
!= reg_access_end
) {
884 access_record
*src
= find_next_rename(search_start
, reg_access_end
,
886 if (src
!= reg_access_end
) {
887 result
[src
->reg
].new_reg
= trgt
->reg
;
888 result
[src
->reg
].valid
= true;
889 trgt
->end
= src
->end
;
891 /* Since we only search forward, don't remove the renamed
892 * register just now, only mark it. */
895 if (first_erase
== reg_access_end
)
898 search_start
= src
+ 1;
900 /* Moving to the next target register it is time to remove
901 * the already merged registers from the search range */
902 if (first_erase
!= reg_access_end
) {
903 access_record
*outp
= first_erase
;
904 access_record
*inp
= first_erase
+ 1;
906 while (inp
!= reg_access_end
) {
912 reg_access_end
= outp
;
913 first_erase
= reg_access_end
;
916 search_start
= trgt
+ 1;
919 ralloc_free(reg_access
);
922 /* Code below used for debugging */
924 static const char swizzle_txt
[] = "xyzw";
926 static const char *tgsi_file_names
[PROGRAM_FILE_MAX
] = {
927 "TEMP", "ARRAY", "IN", "OUT", "STATE", "CONST",
928 "UNIFORM", "WO", "ADDR", "SAMPLER", "SV", "UNDEF",
929 "IMM", "BUF", "MEM", "IMAGE"
933 void dump_instruction(int line
, prog_scope
*scope
,
934 const glsl_to_tgsi_instruction
& inst
)
936 const struct tgsi_opcode_info
*info
= tgsi_get_opcode_info(inst
.op
);
938 int indent
= scope
->nesting_depth();
939 if ((scope
->type() == switch_case_branch
||
940 scope
->type() == switch_default_branch
) &&
941 (info
->opcode
== TGSI_OPCODE_CASE
||
942 info
->opcode
== TGSI_OPCODE_DEFAULT
))
945 if (info
->opcode
== TGSI_OPCODE_ENDIF
||
946 info
->opcode
== TGSI_OPCODE_ELSE
||
947 info
->opcode
== TGSI_OPCODE_ENDLOOP
||
948 info
->opcode
== TGSI_OPCODE_ENDSWITCH
)
951 cerr
<< setw(4) << line
<< ": ";
952 for (int i
= 0; i
< indent
; ++i
)
954 cerr
<< tgsi_get_opcode_name(info
->opcode
) << " ";
956 bool has_operators
= false;
957 for (unsigned j
= 0; j
< num_inst_dst_regs(&inst
); j
++) {
958 has_operators
= true;
962 const st_dst_reg
& dst
= inst
.dst
[j
];
963 cerr
<< tgsi_file_names
[dst
.file
];
965 if (dst
.file
== PROGRAM_ARRAY
)
966 cerr
<< "(" << dst
.array_id
<< ")";
968 cerr
<< "[" << dst
.index
<< "]";
970 if (dst
.writemask
!= TGSI_WRITEMASK_XYZW
) {
972 if (dst
.writemask
& TGSI_WRITEMASK_X
) cerr
<< "x";
973 if (dst
.writemask
& TGSI_WRITEMASK_Y
) cerr
<< "y";
974 if (dst
.writemask
& TGSI_WRITEMASK_Z
) cerr
<< "z";
975 if (dst
.writemask
& TGSI_WRITEMASK_W
) cerr
<< "w";
981 for (unsigned j
= 0; j
< num_inst_src_regs(&inst
); j
++) {
985 const st_src_reg
& src
= inst
.src
[j
];
986 cerr
<< tgsi_file_names
[src
.file
]
987 << "[" << src
.index
<< "]";
988 if (src
.swizzle
!= SWIZZLE_XYZW
) {
990 for (int idx
= 0; idx
< 4; ++idx
) {
991 int swz
= GET_SWZ(src
.swizzle
, idx
);
993 cerr
<< swizzle_txt
[swz
];
999 if (inst
.tex_offset_num_offset
> 0) {
1000 cerr
<< ", TEXOFS: ";
1001 for (unsigned j
= 0; j
< inst
.tex_offset_num_offset
; j
++) {
1005 const st_src_reg
& src
= inst
.tex_offsets
[j
];
1006 cerr
<< tgsi_file_names
[src
.file
]
1007 << "[" << src
.index
<< "]";
1008 if (src
.swizzle
!= SWIZZLE_XYZW
) {
1010 for (int idx
= 0; idx
< 4; ++idx
) {
1011 int swz
= GET_SWZ(src
.swizzle
, idx
);
1013 cerr
<< swizzle_txt
[swz
];