~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/gallium/drivers/r600/sfn/sfn_liverange.cpp

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 
54
 
prog_scope_storage::prog_scope_storage(int n):
55
 
   current_slot(0),
56
 
   storage(n)
57
 
{
58
 
}
59
 
 
60
 
prog_scope_storage::~prog_scope_storage()
61
 
{
62
 
}
63
 
 
64
 
prog_scope*
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
 
 
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
 
 
84
 
prog_scope::prog_scope():
85
 
   prog_scope(nullptr, undefined_scope, -1, -1, -1)
86
 
{
87
 
}
88
 
 
89
 
prog_scope_type prog_scope::type() const
90
 
{
91
 
   return scope_type;
92
 
}
93
 
 
94
 
prog_scope *prog_scope::parent() const
95
 
{
96
 
   return parent_scope;
97
 
}
98
 
 
99
 
int prog_scope::nesting_depth() const
100
 
{
101
 
   return scope_nesting_depth;
102
 
}
103
 
 
104
 
bool prog_scope::is_loop() const
105
 
{
106
 
   return (scope_type == loop_body);
107
 
}
108
 
 
109
 
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
 
 
120
 
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
 
 
131
 
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
 
 
145
 
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
 
 
160
 
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
 
 
171
 
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
 
 
182
 
bool prog_scope::contains_range_of(const prog_scope& other) const
183
 
{
184
 
   return (begin() <= other.begin()) && (end() >= other.end());
185
 
}
186
 
 
187
 
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
 
 
195
 
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
 
 
206
 
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
 
 
214
 
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
 
 
226
 
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
 
 
233
 
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
 
 
249
 
int prog_scope::id() const
250
 
{
251
 
   return scope_id;
252
 
}
253
 
 
254
 
int prog_scope::begin() const
255
 
{
256
 
   return scope_begin;
257
 
}
258
 
 
259
 
int prog_scope::end() const
260
 
{
261
 
   return scope_end;
262
 
}
263
 
 
264
 
void prog_scope::set_end(int end)
265
 
{
266
 
   if (scope_end == -1)
267
 
      scope_end = end;
268
 
}
269
 
 
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
 
 
280
 
int prog_scope::loop_break_line() const
281
 
{
282
 
   return break_loop_line;
283
 
}
284
 
 
285
 
temp_access::temp_access():
286
 
   access_mask(0),
287
 
   needs_component_tracking(false),
288
 
   is_array_element(false)
289
 
{
290
 
}
291
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
604
 
bool temp_comp_access::conditional_ifelse_write_in_loop() const
605
 
{
606
 
   return conditionality_in_loop_id <= conditionality_unresolved;
607
 
}
608
 
 
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
 
 
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
 
      /* Propagate 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
 
 
735
 
   bool operator < (const register_merge_record& rhs) const {
736
 
      return begin < rhs.begin;
737
 
   }
738
 
};
739
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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>
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