• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2017-2019 Gert Wollny
3  *
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:
10  *
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
13  * Software.
14  *
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.
22  */
23 
24 #include "sfn_liverange.h"
25 #include "sfn_debug.h"
26 #include "sfn_value.h"
27 #include "sfn_value_gpr.h"
28 
29 #include "program/prog_instruction.h"
30 #include "util/bitscan.h"
31 #include "util/u_math.h"
32 
33 #include <limits>
34 #include <cstdlib>
35 #include <iomanip>
36 
37 /* std::sort is significantly faster than qsort */
38 #include <algorithm>
39 
40 /* If <windows.h> is included this is defined and clashes with
41  * std::numeric_limits<>::max()
42  */
43 #ifdef max
44 #undef max
45 #endif
46 
47 
48 namespace r600 {
49 
50 using std::numeric_limits;
51 using std::unique_ptr;
52 using std::setw;
53 
prog_scope_storage(int n)54 prog_scope_storage::prog_scope_storage(int n):
55    current_slot(0),
56    storage(n)
57 {
58 }
59 
~prog_scope_storage()60 prog_scope_storage::~prog_scope_storage()
61 {
62 }
63 
64 prog_scope*
create(prog_scope * p,prog_scope_type type,int id,int lvl,int s_begin)65 prog_scope_storage::create(prog_scope *p, prog_scope_type type, int id,
66                            int lvl, int s_begin)
67 {
68    storage[current_slot] = prog_scope(p, type, id, lvl, s_begin);
69    return &storage[current_slot++];
70 }
71 
prog_scope(prog_scope * parent,prog_scope_type type,int id,int depth,int scope_begin)72 prog_scope::prog_scope(prog_scope *parent, prog_scope_type type, int id,
73                        int depth, int scope_begin):
74    scope_type(type),
75    scope_id(id),
76    scope_nesting_depth(depth),
77    scope_begin(scope_begin),
78    scope_end(-1),
79    break_loop_line(numeric_limits<int>::max()),
80    parent_scope(parent)
81 {
82 }
83 
prog_scope()84 prog_scope::prog_scope():
85    prog_scope(nullptr, undefined_scope, -1, -1, -1)
86 {
87 }
88 
type() const89 prog_scope_type prog_scope::type() const
90 {
91    return scope_type;
92 }
93 
parent() const94 prog_scope *prog_scope::parent() const
95 {
96    return parent_scope;
97 }
98 
nesting_depth() const99 int prog_scope::nesting_depth() const
100 {
101    return scope_nesting_depth;
102 }
103 
is_loop() const104 bool prog_scope::is_loop() const
105 {
106    return (scope_type == loop_body);
107 }
108 
is_in_loop() const109 bool prog_scope::is_in_loop() const
110 {
111    if (scope_type == loop_body)
112       return true;
113 
114    if (parent_scope)
115       return parent_scope->is_in_loop();
116 
117    return false;
118 }
119 
innermost_loop() const120 const prog_scope *prog_scope::innermost_loop() const
121 {
122    if (scope_type == loop_body)
123       return this;
124 
125    if (parent_scope)
126       return parent_scope->innermost_loop();
127 
128    return nullptr;
129 }
130 
outermost_loop() const131 const prog_scope *prog_scope::outermost_loop() const
132 {
133    const prog_scope *loop = nullptr;
134    const prog_scope *p = this;
135 
136    do {
137       if (p->type() == loop_body)
138          loop = p;
139       p = p->parent();
140    } while (p);
141 
142    return loop;
143 }
144 
is_child_of_ifelse_id_sibling(const prog_scope * scope) const145 bool prog_scope::is_child_of_ifelse_id_sibling(const prog_scope *scope) const
146 {
147    const prog_scope *my_parent = in_parent_ifelse_scope();
148    while (my_parent) {
149       /* is a direct child? */
150       if (my_parent == scope)
151          return false;
152       /* is a child of the conditions sibling? */
153       if (my_parent->id() == scope->id())
154          return true;
155       my_parent = my_parent->in_parent_ifelse_scope();
156    }
157    return false;
158 }
159 
is_child_of(const prog_scope * scope) const160 bool prog_scope::is_child_of(const prog_scope *scope) const
161 {
162    const prog_scope *my_parent = parent();
163    while (my_parent) {
164       if (my_parent == scope)
165          return true;
166       my_parent = my_parent->parent();
167    }
168    return false;
169 }
170 
enclosing_conditional() const171 const prog_scope *prog_scope::enclosing_conditional() const
172 {
173    if (is_conditional())
174       return this;
175 
176    if (parent_scope)
177       return parent_scope->enclosing_conditional();
178 
179    return nullptr;
180 }
181 
contains_range_of(const prog_scope & other) const182 bool prog_scope::contains_range_of(const prog_scope& other) const
183 {
184    return (begin() <= other.begin()) && (end() >= other.end());
185 }
186 
is_conditional() const187 bool prog_scope::is_conditional() const
188 {
189    return scope_type == if_branch ||
190          scope_type == else_branch ||
191          scope_type == switch_case_branch ||
192          scope_type == switch_default_branch;
193 }
194 
in_else_scope() const195 const prog_scope *prog_scope::in_else_scope() const
196 {
197    if (scope_type == else_branch)
198       return this;
199 
200    if (parent_scope)
201       return parent_scope->in_else_scope();
202 
203    return nullptr;
204 }
205 
in_parent_ifelse_scope() const206 const prog_scope *prog_scope::in_parent_ifelse_scope() const
207 {
208         if (parent_scope)
209                 return parent_scope->in_ifelse_scope();
210         else
211                 return nullptr;
212 }
213 
in_ifelse_scope() const214 const prog_scope *prog_scope::in_ifelse_scope() const
215 {
216    if (scope_type == if_branch ||
217        scope_type == else_branch)
218       return this;
219 
220    if (parent_scope)
221       return parent_scope->in_ifelse_scope();
222 
223    return nullptr;
224 }
225 
is_switchcase_scope_in_loop() const226 bool prog_scope::is_switchcase_scope_in_loop() const
227 {
228    return (scope_type == switch_case_branch ||
229            scope_type == switch_default_branch) &&
230          is_in_loop();
231 }
232 
break_is_for_switchcase() const233 bool prog_scope::break_is_for_switchcase() const
234 {
235    if (scope_type == loop_body)
236       return false;
237 
238    if (scope_type == switch_case_branch ||
239        scope_type == switch_default_branch ||
240        scope_type == switch_body)
241       return true;
242 
243    if (parent_scope)
244       return parent_scope->break_is_for_switchcase();
245 
246    return false;
247 }
248 
id() const249 int prog_scope::id() const
250 {
251    return scope_id;
252 }
253 
begin() const254 int prog_scope::begin() const
255 {
256    return scope_begin;
257 }
258 
end() const259 int prog_scope::end() const
260 {
261    return scope_end;
262 }
263 
set_end(int end)264 void prog_scope::set_end(int end)
265 {
266    if (scope_end == -1)
267       scope_end = end;
268 }
269 
set_loop_break_line(int line)270 void prog_scope::set_loop_break_line(int line)
271 {
272    if (scope_type == loop_body) {
273       break_loop_line = MIN2(break_loop_line, line);
274    } else {
275       if (parent_scope)
276          parent()->set_loop_break_line(line);
277    }
278 }
279 
loop_break_line() const280 int prog_scope::loop_break_line() const
281 {
282    return break_loop_line;
283 }
284 
temp_access()285 temp_access::temp_access():
286    access_mask(0),
287    needs_component_tracking(false),
288    is_array_element(false)
289 {
290 }
291 
update_access_mask(int mask)292 void temp_access::update_access_mask(int mask)
293 {
294    if (access_mask && access_mask != mask)
295       needs_component_tracking = true;
296    access_mask |= mask;
297 }
298 
record_write(int line,prog_scope * scope,int writemask,bool is_array_elm)299 void temp_access::record_write(int line, prog_scope *scope, int writemask, bool is_array_elm)
300 {
301 
302 
303    update_access_mask(writemask);
304    is_array_element |= is_array_elm;
305 
306    if (writemask & WRITEMASK_X)
307       comp[0].record_write(line, scope);
308    if (writemask & WRITEMASK_Y)
309       comp[1].record_write(line, scope);
310    if (writemask & WRITEMASK_Z)
311       comp[2].record_write(line, scope);
312    if (writemask & WRITEMASK_W)
313       comp[3].record_write(line, scope);
314 }
315 
record_read(int line,prog_scope * scope,int readmask,bool is_array_elm)316 void temp_access::record_read(int line, prog_scope *scope, int readmask, bool is_array_elm)
317 {
318    update_access_mask(readmask);
319    is_array_element |= is_array_elm;
320 
321    if (readmask & WRITEMASK_X)
322       comp[0].record_read(line, scope);
323    if (readmask & WRITEMASK_Y)
324       comp[1].record_read(line, scope);
325    if (readmask & WRITEMASK_Z)
326       comp[2].record_read(line, scope);
327    if (readmask & WRITEMASK_W)
328       comp[3].record_read(line, scope);
329 }
330 
make_live_range(int b,int e)331 inline static register_live_range make_live_range(int b, int e)
332 {
333    register_live_range lt;
334    lt.begin = b;
335    lt.end = e;
336    lt.is_array_elm = false;
337    return lt;
338 }
339 
get_required_live_range()340 register_live_range temp_access::get_required_live_range()
341 {
342    register_live_range result = make_live_range(-1, -1);
343 
344    unsigned mask = access_mask;
345    while (mask) {
346       unsigned chan = u_bit_scan(&mask);
347       register_live_range lt = comp[chan].get_required_live_range();
348 
349       if (lt.begin >= 0) {
350          if ((result.begin < 0) || (result.begin > lt.begin))
351             result.begin = lt.begin;
352       }
353 
354       if (lt.end > result.end)
355          result.end = lt.end;
356 
357       if (!needs_component_tracking)
358          break;
359    }
360    result.is_array_elm = is_array_element;
361 
362    return result;
363 }
364 
365 const int
366 temp_comp_access::conditionality_untouched = std::numeric_limits<int>::max();
367 
368 const int
369 temp_comp_access::write_is_unconditional = std::numeric_limits<int>::max() - 1;
370 
371 
temp_comp_access()372 temp_comp_access::temp_comp_access():
373    last_read_scope(nullptr),
374    first_read_scope(nullptr),
375    first_write_scope(nullptr),
376    first_write(-1),
377    last_read(-1),
378    last_write(-1),
379    first_read(numeric_limits<int>::max()),
380    conditionality_in_loop_id(conditionality_untouched),
381    if_scope_write_flags(0),
382    next_ifelse_nesting_depth(0),
383    current_unpaired_if_write_scope(nullptr),
384    was_written_in_current_else_scope(false)
385 {
386 }
387 
record_read(int line,prog_scope * scope)388 void temp_comp_access::record_read(int line, prog_scope *scope)
389 {
390    last_read_scope = scope;
391    if (last_read < line)
392       last_read = line;
393 
394    if (first_read > line) {
395       first_read = line;
396       first_read_scope = scope;
397    }
398 
399    /* If the conditionality of the first write is already resolved then
400     * no further checks are required.
401     */
402    if (conditionality_in_loop_id == write_is_unconditional ||
403        conditionality_in_loop_id == write_is_conditional)
404       return;
405 
406    /* Check whether we are in a condition within a loop */
407    const prog_scope *ifelse_scope = scope->in_ifelse_scope();
408    const prog_scope *enclosing_loop;
409    if (ifelse_scope && (enclosing_loop = ifelse_scope->innermost_loop())) {
410 
411       /* If we have either not yet written to this register nor writes are
412        * resolved as unconditional in the enclosing loop then check whether
413        * we read before write in an IF/ELSE branch.
414        */
415       if ((conditionality_in_loop_id != write_is_conditional) &&
416           (conditionality_in_loop_id != enclosing_loop->id())) {
417 
418          if (current_unpaired_if_write_scope)  {
419 
420             /* Has been written in this or a parent scope? - this makes the temporary
421              * unconditionally set at this point.
422              */
423             if (scope->is_child_of(current_unpaired_if_write_scope))
424                return;
425 
426             /* Has been written in the same scope before it was read? */
427             if (ifelse_scope->type() == if_branch) {
428                if (current_unpaired_if_write_scope->id() == scope->id())
429                   return;
430             } else {
431                if (was_written_in_current_else_scope)
432                   return;
433             }
434          }
435 
436          /* The temporary was read (conditionally) before it is written, hence
437           * it should survive a loop. This can be signaled like if it were
438           * conditionally written.
439           */
440          conditionality_in_loop_id = write_is_conditional;
441       }
442    }
443 }
444 
record_write(int line,prog_scope * scope)445 void temp_comp_access::record_write(int line, prog_scope *scope)
446 {
447    last_write = line;
448 
449    if (first_write < 0) {
450       first_write = line;
451       first_write_scope = scope;
452 
453       /* If the first write we encounter is not in a conditional branch, or
454        * the conditional write is not within a loop, then this is to be
455        * considered an unconditional dominant write.
456        */
457       const prog_scope *conditional = scope->enclosing_conditional();
458       if (!conditional || !conditional->innermost_loop()) {
459          conditionality_in_loop_id = write_is_unconditional;
460       }
461    }
462 
463    /* The conditionality of the first write is already resolved. */
464    if (conditionality_in_loop_id == write_is_unconditional ||
465        conditionality_in_loop_id == write_is_conditional)
466       return;
467 
468    /* If the nesting depth is larger than the supported level,
469     * then we assume conditional writes.
470     */
471    if (next_ifelse_nesting_depth >= supported_ifelse_nesting_depth) {
472       conditionality_in_loop_id = write_is_conditional;
473       return;
474    }
475 
476    /* If we are in an IF/ELSE scope within a loop and the loop has not
477     * been resolved already, then record this write.
478     */
479    const prog_scope *ifelse_scope = scope->in_ifelse_scope();
480    if (ifelse_scope && ifelse_scope->innermost_loop() &&
481        ifelse_scope->innermost_loop()->id()  != conditionality_in_loop_id)
482       record_ifelse_write(*ifelse_scope);
483 }
484 
record_ifelse_write(const prog_scope & scope)485 void temp_comp_access::record_ifelse_write(const prog_scope& scope)
486 {
487    if (scope.type() == if_branch) {
488       /* The first write in an IF branch within a loop implies unresolved
489        * conditionality (if it was untouched or unconditional before).
490        */
491       conditionality_in_loop_id = conditionality_unresolved;
492       was_written_in_current_else_scope = false;
493       record_if_write(scope);
494    } else {
495       was_written_in_current_else_scope = true;
496       record_else_write(scope);
497    }
498 }
499 
record_if_write(const prog_scope & scope)500 void temp_comp_access::record_if_write(const prog_scope& scope)
501 {
502    /* Don't record write if this IF scope if it ...
503     * - is not the first write in this IF scope,
504     * - has already been written in a parent IF scope.
505     * In both cases this write is a secondary write that doesn't contribute
506     * to resolve conditionality.
507     *
508     * Record the write if it
509     * - is the first one (obviously),
510     * - happens in an IF branch that is a child of the ELSE branch of the
511     *   last active IF/ELSE pair. In this case recording this write is used to
512     *   established whether the write is (un-)conditional in the scope enclosing
513     *   this outer IF/ELSE pair.
514     */
515    if (!current_unpaired_if_write_scope ||
516        (current_unpaired_if_write_scope->id() != scope.id() &&
517         scope.is_child_of_ifelse_id_sibling(current_unpaired_if_write_scope)))  {
518       if_scope_write_flags |= 1 << next_ifelse_nesting_depth;
519       current_unpaired_if_write_scope = &scope;
520       next_ifelse_nesting_depth++;
521    }
522 }
523 
record_else_write(const prog_scope & scope)524 void temp_comp_access::record_else_write(const prog_scope& scope)
525 {
526    int mask = 1 << (next_ifelse_nesting_depth - 1);
527 
528    /* If the temporary was written in an IF branch on the same scope level
529     * and this branch is the sibling of this ELSE branch, then we have a
530     * pair of writes that makes write access to this temporary unconditional
531     * in the enclosing scope.
532     */
533 
534    if ((if_scope_write_flags & mask) &&
535        (scope.id() == current_unpaired_if_write_scope->id())) {
536           --next_ifelse_nesting_depth;
537          if_scope_write_flags &= ~mask;
538 
539          /* The following code deals with propagating unconditionality from
540           * inner levels of nested IF/ELSE to the outer levels like in
541           *
542           * 1: var t;
543           * 2: if (a) {        <- start scope A
544           * 3:    if (b)
545           * 4:         t = ...
546           * 5:    else
547           * 6:         t = ...
548           * 7: } else {        <- start scope B
549           * 8:    if (c)
550           * 9:         t = ...
551           * A:    else         <- start scope C
552           * B:         t = ...
553           * C: }
554           *
555           */
556 
557          const prog_scope *parent_ifelse = scope.parent()->in_ifelse_scope();
558 
559          if (1 << (next_ifelse_nesting_depth - 1) & if_scope_write_flags) {
560             /* We are at the end of scope C and already recorded a write
561              * within an IF scope (A), the sibling of the parent ELSE scope B,
562              * and it is not yet resolved. Mark that as the last relevant
563              * IF scope. Below the write will be resolved for the A/B
564              * scope pair.
565              */
566             current_unpaired_if_write_scope = parent_ifelse;
567          } else {
568             current_unpaired_if_write_scope = nullptr;
569          }
570 	 /* Promote the first write scope to the enclosing scope because
571 	  * the current IF/ELSE pair is now irrelevant for the analysis.
572 	  * This is also required to evaluate the minimum life time for t in
573 	  * {
574 	  *    var t;
575 	  *    if (a)
576 	  *      t = ...
577 	  *    else
578 	  *      t = ...
579 	  *    x = t;
580 	  *    ...
581 	  * }
582 	  */
583 	 first_write_scope = scope.parent();
584 
585          /* If some parent is IF/ELSE and in a loop then propagate the
586           * write to that scope. Otherwise the write is unconditional
587           * because it happens in both corresponding IF/ELSE branches
588           * in this loop, and hence, record the loop id to signal the
589           * resolution.
590           */
591          if (parent_ifelse && parent_ifelse->is_in_loop()) {
592             record_ifelse_write(*parent_ifelse);
593          } else {
594             conditionality_in_loop_id = scope.innermost_loop()->id();
595          }
596    } else {
597      /* The temporary was not written in the IF branch corresponding
598       * to this ELSE branch, hence the write is conditional.
599       */
600       conditionality_in_loop_id = write_is_conditional;
601    }
602 }
603 
conditional_ifelse_write_in_loop() const604 bool temp_comp_access::conditional_ifelse_write_in_loop() const
605 {
606    return conditionality_in_loop_id <= conditionality_unresolved;
607 }
608 
propagate_live_range_to_dominant_write_scope()609 void temp_comp_access::propagate_live_range_to_dominant_write_scope()
610 {
611    first_write = first_write_scope->begin();
612    int lr = first_write_scope->end();
613 
614    if (last_read < lr)
615       last_read = lr;
616 }
617 
get_required_live_range()618 register_live_range temp_comp_access::get_required_live_range()
619 {
620    bool keep_for_full_loop = false;
621 
622    /* This register component is not used at all, or only read,
623     * mark it as unused and ignore it when renaming.
624     * glsl_to_tgsi_visitor::renumber_registers will take care of
625     * eliminating registers that are not written to.
626     */
627    if (last_write < 0)
628       return make_live_range(-1, -1);
629 
630    assert(first_write_scope);
631 
632    /* Only written to, just make sure the register component is not
633     * reused in the range it is used to write to
634     */
635    if (!last_read_scope)
636       return make_live_range(first_write, last_write + 1);
637 
638    const prog_scope *enclosing_scope_first_read = first_read_scope;
639    const prog_scope *enclosing_scope_first_write = first_write_scope;
640 
641    /* We read before writing in a loop
642     * hence the value must survive the loops
643     */
644    if ((first_read <= first_write) &&
645        first_read_scope->is_in_loop()) {
646       keep_for_full_loop = true;
647       enclosing_scope_first_read = first_read_scope->outermost_loop();
648    }
649 
650    /* A conditional write within a (nested) loop must survive the outermost
651     * loop if the last read was not within the same scope.
652     */
653    const prog_scope *conditional = enclosing_scope_first_write->enclosing_conditional();
654    if (conditional && !conditional->contains_range_of(*last_read_scope) &&
655        (conditional->is_switchcase_scope_in_loop() ||
656         conditional_ifelse_write_in_loop())) {
657          keep_for_full_loop = true;
658          enclosing_scope_first_write = conditional->outermost_loop();
659    }
660 
661    /* Evaluate the scope that is shared by all: required first write scope,
662     * required first read before write scope, and last read scope.
663     */
664    const prog_scope *enclosing_scope = enclosing_scope_first_read;
665    if (enclosing_scope_first_write->contains_range_of(*enclosing_scope))
666       enclosing_scope = enclosing_scope_first_write;
667 
668    if (last_read_scope->contains_range_of(*enclosing_scope))
669       enclosing_scope = last_read_scope;
670 
671    while (!enclosing_scope->contains_range_of(*enclosing_scope_first_write) ||
672           !enclosing_scope->contains_range_of(*last_read_scope)) {
673       enclosing_scope = enclosing_scope->parent();
674       assert(enclosing_scope);
675    }
676 
677    /* Propagate the last read scope to the target scope */
678    while (enclosing_scope->nesting_depth() < last_read_scope->nesting_depth()) {
679       /* If the read is in a loop and we have to move up the scope we need to
680        * extend the live range to the end of this current loop because at this
681        * point we don't know whether the component was written before
682        * un-conditionally in the same loop.
683        */
684       if (last_read_scope->is_loop())
685          last_read = last_read_scope->end();
686 
687       last_read_scope = last_read_scope->parent();
688    }
689 
690    /* If the variable has to be kept for the whole loop, and we
691     * are currently in a loop, then propagate the live range.
692     */
693    if (keep_for_full_loop && first_write_scope->is_loop())
694       propagate_live_range_to_dominant_write_scope();
695 
696    /* Propagate the first_dominant_write scope to the target scope */
697    while (enclosing_scope->nesting_depth() < first_write_scope->nesting_depth()) {
698       /* Propagate live_range if there was a break in a loop and the write was
699        * after the break inside that loop. Note, that this is only needed if
700        * we move up in the scopes.
701        */
702       if (first_write_scope->loop_break_line() < first_write) {
703          keep_for_full_loop = true;
704 	 propagate_live_range_to_dominant_write_scope();
705       }
706 
707       first_write_scope = first_write_scope->parent();
708 
709       /* Propagte live_range if we are now in a loop */
710       if (keep_for_full_loop && first_write_scope->is_loop())
711 	  propagate_live_range_to_dominant_write_scope();
712    }
713 
714    /* The last write past the last read is dead code, but we have to
715     * ensure that the component is not reused too early, hence extend the
716     * live_range past the last write.
717     */
718    if (last_write >= last_read)
719       last_read = last_write + 1;
720 
721    /* Here we are at the same scope, all is resolved */
722    return make_live_range(first_write, last_read);
723 }
724 
725 /* Helper class for sorting and searching the registers based
726  * on live ranges. */
727 class register_merge_record {
728 public:
729    int begin;
730    int end;
731    int reg;
732    bool erase;
733    bool is_array_elm;
734 
operator <(const register_merge_record & rhs) const735    bool operator < (const register_merge_record& rhs) const {
736       return begin < rhs.begin;
737    }
738 };
739 
LiverangeEvaluator()740 LiverangeEvaluator::LiverangeEvaluator():
741    line(0),
742    loop_id(1),
743    if_id(1),
744    switch_id(0),
745    is_at_end(false),
746    n_scopes(1),
747    cur_scope(nullptr)
748 {
749 }
750 
run(const Shader & shader,std::vector<register_live_range> & register_live_ranges)751 void LiverangeEvaluator::run(const Shader& shader,
752                              std::vector<register_live_range>& register_live_ranges)
753 {
754    temp_acc.resize(register_live_ranges.size());
755    fill(temp_acc.begin(), temp_acc.end(), temp_access());
756 
757    sfn_log << SfnLog::merge << "have " << temp_acc.size() << " temps\n";
758 
759    for (const auto& block: shader.m_ir) {
760       for (const auto& ir: block) {
761          switch (ir->type()) {
762          case Instruction::cond_if:
763          case Instruction::cond_else:
764          case Instruction::loop_begin:
765             ++n_scopes;
766          default:
767             ;
768          }
769       }
770    }
771 
772    scopes.reset(new prog_scope_storage(n_scopes));
773 
774    cur_scope = scopes->create(nullptr, outer_scope, 0, 0, line);
775 
776    line = 0;
777 
778    for (auto& v: shader.m_temp) {
779       if (v.second->type() == Value::gpr) {
780          sfn_log << SfnLog::merge << "Record " << *v.second << "\n";
781          const auto& g = static_cast<const GPRValue&>(*v.second);
782          if (g.is_input()) {
783             sfn_log << SfnLog::merge << "Record INPUT write for "
784                     << g << " in " << temp_acc.size() << " temps\n";
785             temp_acc[g.sel()].record_write(line, cur_scope, 1 << g.chan(), false);
786             temp_acc[g.sel()].record_read(line, cur_scope, 1 << g.chan(), false);
787          }
788          if (g.keep_alive()) {
789             sfn_log << SfnLog::merge << "Record KEEP ALIVE for "
790                     << g << " in " << temp_acc.size() << " temps\n";
791             temp_acc[g.sel()].record_read(0x7fffff, cur_scope, 1 << g.chan(), false);
792          }
793       }
794    }
795 
796    for (const auto& block: shader.m_ir)
797       for (const auto& ir: block)  {
798          ir->evalue_liveness(*this);
799          if (ir->type() != Instruction::alu ||
800              static_cast<const AluInstruction&>(*ir).flag(alu_last_instr))
801             ++line;
802       }
803 
804    assert(cur_scope->type() == outer_scope);
805    cur_scope->set_end(line);
806    is_at_end = true;
807 
808    get_required_live_ranges(register_live_ranges);
809 }
810 
811 
record_read(const Value & src,bool is_array_elm)812 void LiverangeEvaluator::record_read(const Value& src, bool is_array_elm)
813 {
814    sfn_log << SfnLog::merge << "Record read l:" << line << " reg:" << src << "\n";
815    if (src.type() == Value::gpr) {
816       const GPRValue& v = static_cast<const GPRValue&>(src);
817       if (v.chan() < 4)
818          temp_acc[v.sel()].record_read(v.keep_alive() ? 0x7fffff: line, cur_scope, 1 << v.chan(), is_array_elm);
819       return;
820    } else if (src.type() == Value::gpr_array_value) {
821       const GPRArrayValue& v = static_cast<const GPRArrayValue&>(src);
822       v.record_read(*this);
823    } else if (src.type() == Value::kconst) {
824       const UniformValue& v = static_cast<const UniformValue&>(src);
825       if (v.addr())
826          record_read(*v.addr(),is_array_elm);
827    }
828 }
829 
record_write(const Value & src,bool is_array_elm)830 void LiverangeEvaluator::record_write(const Value& src, bool is_array_elm)
831 {
832    sfn_log << SfnLog::merge << "Record write for "
833            << src << " in " << temp_acc.size() << " temps\n";
834 
835    if (src.type() == Value::gpr) {
836       const GPRValue& v = static_cast<const GPRValue&>(src);
837       assert(v.sel() < temp_acc.size());
838       if (v.chan() < 4)
839          temp_acc[v.sel()].record_write(line, cur_scope, 1 << v.chan(), is_array_elm);
840       return;
841    } else if (src.type() == Value::gpr_array_value) {
842       const GPRArrayValue& v = static_cast<const GPRArrayValue&>(src);
843       v.record_write(*this);
844    } else if (src.type() == Value::kconst) {
845       const UniformValue& v = static_cast<const UniformValue&>(src);
846       if (v.addr())
847          record_write(*v.addr(),is_array_elm);
848    }
849 }
850 
record_read(const GPRVector & src)851 void LiverangeEvaluator::record_read(const GPRVector& src)
852 {
853    for (int i = 0; i < 4; ++i)
854       if (src.reg_i(i))
855          record_read(*src.reg_i(i));
856 }
857 
record_write(const GPRVector & dst)858 void LiverangeEvaluator::record_write(const GPRVector& dst)
859 {
860    for (int i = 0; i < 4; ++i)
861       if (dst.reg_i(i))
862          record_write(*dst.reg_i(i));
863 }
864 
get_required_live_ranges(std::vector<register_live_range> & register_live_ranges)865 void LiverangeEvaluator::get_required_live_ranges(std::vector<register_live_range>& register_live_ranges)
866 {
867    sfn_log << SfnLog::merge << "== register live ranges ==========\n";
868    for(unsigned i = 0; i < register_live_ranges.size(); ++i) {
869       sfn_log << SfnLog::merge << setw(4) << i;
870       register_live_ranges[i] = temp_acc[i].get_required_live_range();
871       sfn_log << SfnLog::merge << ": [" << register_live_ranges[i].begin << ", "
872 		   << register_live_ranges[i].end << "]\n";
873    }
874    sfn_log << SfnLog::merge << "==================================\n\n";
875 }
876 
scope_if()877 void LiverangeEvaluator::scope_if()
878 {
879    cur_scope = scopes->create(cur_scope, if_branch, if_id++,
880                               cur_scope->nesting_depth() + 1, line + 1);
881 }
882 
scope_else()883 void LiverangeEvaluator::scope_else()
884 {
885    assert(cur_scope->type() == if_branch);
886    cur_scope->set_end(line - 1);
887    cur_scope = scopes->create(cur_scope->parent(), else_branch,
888                               cur_scope->id(), cur_scope->nesting_depth(),
889                              line + 1);
890 }
891 
scope_endif()892 void LiverangeEvaluator::scope_endif()
893 {
894    cur_scope->set_end(line - 1);
895    cur_scope = cur_scope->parent();
896    assert(cur_scope);
897 }
898 
scope_loop_begin()899 void LiverangeEvaluator::scope_loop_begin()
900 {
901    cur_scope = scopes->create(cur_scope, loop_body, loop_id++,
902                               cur_scope->nesting_depth() + 1, line);
903 }
904 
scope_loop_end()905 void LiverangeEvaluator::scope_loop_end()
906 {
907    assert(cur_scope->type() == loop_body);
908    cur_scope->set_end(line);
909    cur_scope = cur_scope->parent();
910    assert(cur_scope);
911 }
912 
scope_loop_break()913 void LiverangeEvaluator::scope_loop_break()
914 {
915    cur_scope->set_loop_break_line(line);
916 }
917 
918 /* This functions evaluates the register merges by using a binary
919  * search to find suitable merge candidates. */
920 
921 std::vector<rename_reg_pair>
get_temp_registers_remapping(const std::vector<register_live_range> & live_ranges)922 get_temp_registers_remapping(const std::vector<register_live_range>& live_ranges)
923 {
924 
925    std::vector<rename_reg_pair> result(live_ranges.size(), rename_reg_pair{false, false, 0});
926    std::vector<register_merge_record> reg_access;
927 
928    for (unsigned i = 0; i < live_ranges.size(); ++i) {
929       if (live_ranges[i].begin >= 0) {
930          register_merge_record r;
931          r.begin = live_ranges[i].begin;
932          r.end = live_ranges[i].end;
933          r.is_array_elm = live_ranges[i].is_array_elm;
934          r.reg = i;
935          r.erase = false;
936          reg_access.push_back(r);
937       }
938    }
939 
940    std::sort(reg_access.begin(), reg_access.end());
941 
942    for (auto& r : reg_access)
943       sfn_log << SfnLog::merge << "Use Range " <<r.reg << " ["
944               << r.begin << ", "  << r.end << "]\n";
945 
946    auto trgt = reg_access.begin();
947    auto reg_access_end = reg_access.end();
948    auto first_erase = reg_access_end;
949    auto search_start = trgt + 1;
950 
951    while (trgt != reg_access_end) {
952       /* Find the next register that has a live-range starting past the
953        * search start and that is not an array element. Array elements can't
954        * be moved (Moving the whole array could be an option to be implemented later)*/
955 
956       sfn_log << SfnLog::merge << "Next target is "
957               << trgt->reg << "[" << trgt->begin << ", "  << trgt->end << "]\n";
958 
959 
960       auto src = upper_bound(search_start, reg_access_end, trgt->end,
961                              [](int bound, const register_merge_record& m){
962                                     return bound < m.begin && !m.is_array_elm;}
963                              );
964 
965       if (src != reg_access_end) {
966          result[src->reg].new_reg = trgt->reg;
967          result[src->reg].valid = true;
968 
969          sfn_log << SfnLog::merge << "Map "
970                  << src->reg << "[" << src->begin << ", "  << src->end << "] to  "
971                  << trgt->reg << "[" << trgt->begin << ", "  << trgt->end << ":";
972          trgt->end = src->end;
973          sfn_log << SfnLog::merge << trgt->end  << "]\n";
974 
975          /* Since we only search forward, don't remove the renamed
976           * register just now, only mark it. */
977          src->erase = true;
978 
979          if (first_erase == reg_access_end)
980             first_erase = src;
981 
982          search_start = src + 1;
983       } else {
984          /* Moving to the next target register it is time to remove
985           * the already merged registers from the search range */
986          if (first_erase != reg_access_end) {
987 	    auto outp = first_erase;
988 	    auto inp = first_erase + 1;
989 
990             while (inp != reg_access_end) {
991                if (!inp->erase)
992                   *outp++ = *inp;
993                ++inp;
994             }
995 
996             reg_access_end = outp;
997             first_erase = reg_access_end;
998          }
999          ++trgt;
1000          search_start = trgt + 1;
1001       }
1002    }
1003    return result;
1004 }
1005 
1006 } // end ns r600
1007