~ubuntu-branches/ubuntu/precise/mesa/precise-updates

« back to all changes in this revision

Viewing changes to src/gallium/drivers/nvc0/nvc0_pc_optimize.c

  • Committer: Package Import Robot
  • Author(s): Robert Hooker
  • Date: 2012-02-02 12:05:48 UTC
  • mfrom: (1.7.1) (3.3.27 sid)
  • Revision ID: package-import@ubuntu.com-20120202120548-nvkma85jq0h4coix
Tags: 8.0~rc2-0ubuntu4
Drop drisearchdir handling, it is no longer needed with multiarch
and dri-alternates being removed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright 2010 Christoph Bumiller
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 shall be included in
12
 
 * all copies or substantial portions of the Software.
13
 
 *
14
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17
 
 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
 
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19
 
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
 
 * SOFTWARE.
21
 
 */
22
 
 
23
 
#include "nvc0_pc.h"
24
 
#include "nvc0_program.h"
25
 
 
26
 
#define DESCEND_ARBITRARY(j, f)                                 \
27
 
do {                                                            \
28
 
   b->pass_seq = ctx->pc->pass_seq;                             \
29
 
                                                                \
30
 
   for (j = 0; j < 2; ++j)                                      \
31
 
      if (b->out[j] && b->out[j]->pass_seq < ctx->pc->pass_seq) \
32
 
         f(ctx, b->out[j]);                                       \
33
 
} while (0)
34
 
 
35
 
static INLINE boolean
36
 
registers_interfere(struct nv_value *a, struct nv_value *b)
37
 
{
38
 
   if (a->reg.file != b->reg.file)
39
 
      return FALSE;
40
 
   if (NV_IS_MEMORY_FILE(a->reg.file) || NV_IS_MEMORY_FILE(b->reg.file))
41
 
      return FALSE;
42
 
 
43
 
   assert(a->join->reg.id >= 0 && b->join->reg.id >= 0);
44
 
 
45
 
   if (a->join->reg.id < b->join->reg.id) {
46
 
      return (a->join->reg.id + a->reg.size >= b->join->reg.id);
47
 
   } else
48
 
   if (a->join->reg.id > b->join->reg.id) {
49
 
      return (b->join->reg.id + b->reg.size >= a->join->reg.id);
50
 
   }
51
 
 
52
 
   return FALSE;
53
 
}
54
 
 
55
 
static INLINE boolean
56
 
values_equal(struct nv_value *a, struct nv_value *b)
57
 
{
58
 
   if (a->reg.file != b->reg.file || a->reg.size != b->reg.size)
59
 
      return FALSE;
60
 
   if (NV_IS_MEMORY_FILE(a->reg.file))
61
 
      return a->reg.address == b->reg.address;
62
 
   else
63
 
      return a->join->reg.id == b->join->reg.id;
64
 
}
65
 
 
66
 
#if 0
67
 
static INLINE boolean
68
 
inst_commutation_check(struct nv_instruction *a, struct nv_instruction *b)
69
 
{
70
 
   int si, di;
71
 
 
72
 
   for (di = 0; di < 4 && a->def[di]; ++di)
73
 
      for (si = 0; si < 5 && b->src[si]; ++si)
74
 
         if (registers_interfere(a->def[di], b->src[si]->value))
75
 
            return FALSE;
76
 
 
77
 
   return TRUE;
78
 
}
79
 
 
80
 
/* Check whether we can swap the order of the instructions,
81
 
 * where a & b may be either the earlier or the later one.
82
 
 */
83
 
static boolean
84
 
inst_commutation_legal(struct nv_instruction *a, struct nv_instruction *b)
85
 
{
86
 
   return inst_commutation_check(a, b) && inst_commutation_check(b, a);
87
 
}
88
 
#endif
89
 
 
90
 
static INLINE boolean
91
 
inst_removable(struct nv_instruction *nvi)
92
 
{
93
 
   if (nvi->opcode == NV_OP_ST)
94
 
      return FALSE;
95
 
   return (!(nvi->terminator ||
96
 
             nvi->join ||
97
 
             nvi->target ||
98
 
             nvi->fixed ||
99
 
             nvc0_insn_refcount(nvi)));
100
 
}
101
 
 
102
 
/* Check if we do not actually have to emit this instruction. */
103
 
static INLINE boolean
104
 
inst_is_noop(struct nv_instruction *nvi)
105
 
{
106
 
   if (nvi->opcode == NV_OP_UNDEF || nvi->opcode == NV_OP_BIND)
107
 
      return TRUE;
108
 
   if (nvi->terminator || nvi->join)
109
 
      return FALSE;
110
 
   if (nvi->def[0] && nvi->def[0]->join->reg.id < 0)
111
 
      return TRUE;
112
 
   if (nvi->opcode != NV_OP_MOV && nvi->opcode != NV_OP_SELECT)
113
 
      return FALSE;
114
 
   if (nvi->def[0]->reg.file != nvi->src[0]->value->reg.file)
115
 
      return FALSE;
116
 
 
117
 
   if (nvi->src[0]->value->join->reg.id < 0) {
118
 
      NV50_DBGMSG(PROG_IR, "inst_is_noop: orphaned value detected\n");
119
 
      return TRUE;
120
 
   }
121
 
 
122
 
   if (nvi->opcode == NV_OP_SELECT)
123
 
      if (!values_equal(nvi->def[0], nvi->src[1]->value))
124
 
         return FALSE;
125
 
   return values_equal(nvi->def[0], nvi->src[0]->value);
126
 
}
127
 
 
128
 
struct nv_pass {
129
 
   struct nv_pc *pc;
130
 
   int n;
131
 
   void *priv;
132
 
};
133
 
 
134
 
static int
135
 
nv_pass_flatten(struct nv_pass *ctx, struct nv_basic_block *b);
136
 
 
137
 
static void
138
 
nv_pc_pass_pre_emission(void *priv, struct nv_basic_block *b)
139
 
{
140
 
   struct nv_pc *pc = (struct nv_pc *)priv;
141
 
   struct nv_basic_block *in;
142
 
   struct nv_instruction *nvi, *next;
143
 
   int j;
144
 
 
145
 
   /* find first non-empty block emitted before b */
146
 
   for (j = pc->num_blocks - 1; j >= 0 && !pc->bb_list[j]->emit_size; --j);
147
 
 
148
 
   for (; j >= 0; --j) {
149
 
      in = pc->bb_list[j];
150
 
 
151
 
      /* check for no-op branches (BRA $PC+8) */
152
 
      if (in->exit && in->exit->opcode == NV_OP_BRA && in->exit->target == b) {
153
 
         in->emit_size -= 8;
154
 
         pc->emit_size -= 8;
155
 
 
156
 
         for (++j; j < pc->num_blocks; ++j)
157
 
            pc->bb_list[j]->emit_pos -= 8;
158
 
 
159
 
         nvc0_insn_delete(in->exit);
160
 
      }
161
 
      b->emit_pos = in->emit_pos + in->emit_size;
162
 
 
163
 
      if (in->emit_size) /* no more no-op branches to b */
164
 
         break;
165
 
   }
166
 
 
167
 
   pc->bb_list[pc->num_blocks++] = b;
168
 
 
169
 
   /* visit node */
170
 
 
171
 
   for (nvi = b->entry; nvi; nvi = next) {
172
 
      next = nvi->next;
173
 
      if (inst_is_noop(nvi) ||
174
 
          (pc->is_fragprog && nvi->opcode == NV_OP_EXPORT)) {
175
 
         nvc0_insn_delete(nvi);
176
 
      } else
177
 
         b->emit_size += 8;
178
 
   }
179
 
   pc->emit_size += b->emit_size;
180
 
 
181
 
#if NV50_DEBUG & NV50_DEBUG_PROG_IR
182
 
   if (!b->entry)
183
 
      debug_printf("BB:%i is now empty\n", b->id);
184
 
   else
185
 
      debug_printf("BB:%i size = %u\n", b->id, b->emit_size);
186
 
#endif
187
 
}
188
 
 
189
 
static int
190
 
nv_pc_pass2(struct nv_pc *pc, struct nv_basic_block *root)
191
 
{
192
 
   struct nv_pass pass;
193
 
 
194
 
   pass.pc = pc;
195
 
 
196
 
   pc->pass_seq++;
197
 
   nv_pass_flatten(&pass, root);
198
 
 
199
 
   nvc0_pc_pass_in_order(root, nv_pc_pass_pre_emission, pc);
200
 
 
201
 
   return 0;
202
 
}
203
 
 
204
 
int
205
 
nvc0_pc_exec_pass2(struct nv_pc *pc)
206
 
{
207
 
   int i, ret;
208
 
 
209
 
   NV50_DBGMSG(PROG_IR, "preparing %u blocks for emission\n", pc->num_blocks);
210
 
 
211
 
   pc->num_blocks = 0; /* will reorder bb_list */
212
 
 
213
 
   for (i = 0; i < pc->num_subroutines + 1; ++i)
214
 
      if (pc->root[i] && (ret = nv_pc_pass2(pc, pc->root[i])))
215
 
         return ret;
216
 
   return 0;
217
 
}
218
 
 
219
 
static INLINE boolean
220
 
is_cspace_load(struct nv_instruction *nvi)
221
 
{
222
 
   if (!nvi)
223
 
      return FALSE;
224
 
   assert(nvi->indirect != 0);
225
 
   return (nvi->opcode == NV_OP_LD &&
226
 
           nvi->src[0]->value->reg.file >= NV_FILE_MEM_C(0) &&
227
 
           nvi->src[0]->value->reg.file <= NV_FILE_MEM_C(15));
228
 
}
229
 
 
230
 
static INLINE boolean
231
 
is_immd32_load(struct nv_instruction *nvi)
232
 
{
233
 
   if (!nvi)
234
 
      return FALSE;
235
 
   return (nvi->opcode == NV_OP_MOV &&
236
 
           nvi->src[0]->value->reg.file == NV_FILE_IMM &&
237
 
           nvi->src[0]->value->reg.size == 4);
238
 
}
239
 
 
240
 
static INLINE void
241
 
check_swap_src_0_1(struct nv_instruction *nvi)
242
 
{
243
 
   struct nv_ref *src0 = nvi->src[0];
244
 
   struct nv_ref *src1 = nvi->src[1];
245
 
 
246
 
   if (!nv_op_commutative(nvi->opcode) &&
247
 
       NV_BASEOP(nvi->opcode) != NV_OP_SET &&
248
 
       NV_BASEOP(nvi->opcode) != NV_OP_SLCT)
249
 
      return;
250
 
   assert(src0 && src1 && src0->value && src1->value);
251
 
 
252
 
   if (src1->value->reg.file != NV_FILE_GPR)
253
 
      return;
254
 
 
255
 
   if (is_cspace_load(src0->value->insn)) {
256
 
      if (!is_cspace_load(src1->value->insn)) {
257
 
         nvi->src[0] = src1;
258
 
         nvi->src[1] = src0;
259
 
      }
260
 
   } else
261
 
   if (is_immd32_load(src0->value->insn)) {
262
 
      if (!is_cspace_load(src1->value->insn) &&
263
 
          !is_immd32_load(src1->value->insn)) {
264
 
         nvi->src[0] = src1;
265
 
         nvi->src[1] = src0;
266
 
      }
267
 
   }
268
 
 
269
 
   if (nvi->src[0] != src0) {
270
 
      if (NV_BASEOP(nvi->opcode) == NV_OP_SET)
271
 
         nvi->set_cond = nvc0_ir_reverse_cc(nvi->set_cond);
272
 
      else
273
 
      if (NV_BASEOP(nvi->opcode) == NV_OP_SLCT)
274
 
         nvi->set_cond = NV_CC_INVERSE(nvi->set_cond);
275
 
   }
276
 
}
277
 
 
278
 
static void
279
 
nvi_set_indirect_load(struct nv_pc *pc,
280
 
                      struct nv_instruction *nvi, struct nv_value *val)
281
 
{
282
 
   for (nvi->indirect = 0; nvi->indirect < 6 && nvi->src[nvi->indirect];
283
 
        ++nvi->indirect);
284
 
   assert(nvi->indirect < 6);
285
 
   nv_reference(pc, nvi, nvi->indirect, val);
286
 
}
287
 
 
288
 
static int
289
 
nvc0_pass_fold_loads(struct nv_pass *ctx, struct nv_basic_block *b)
290
 
{
291
 
   struct nv_instruction *nvi, *ld;
292
 
   int s;
293
 
 
294
 
   for (nvi = b->entry; nvi; nvi = nvi->next) {
295
 
      check_swap_src_0_1(nvi);
296
 
 
297
 
      for (s = 0; s < 3 && nvi->src[s]; ++s) {
298
 
         ld = nvi->src[s]->value->insn;
299
 
         if (!ld || (ld->opcode != NV_OP_LD && ld->opcode != NV_OP_MOV))
300
 
            continue;
301
 
         if (!nvc0_insn_can_load(nvi, s, ld))
302
 
            continue;
303
 
 
304
 
         /* fold it ! */
305
 
         nv_reference(ctx->pc, nvi, s, ld->src[0]->value);
306
 
         if (ld->indirect >= 0)
307
 
            nvi_set_indirect_load(ctx->pc, nvi, ld->src[ld->indirect]->value);
308
 
 
309
 
         if (!nvc0_insn_refcount(ld))
310
 
            nvc0_insn_delete(ld);
311
 
      }
312
 
   }
313
 
   DESCEND_ARBITRARY(s, nvc0_pass_fold_loads);
314
 
 
315
 
   return 0;
316
 
}
317
 
 
318
 
/* NOTE: Assumes loads have not yet been folded. */
319
 
static int
320
 
nv_pass_lower_mods(struct nv_pass *ctx, struct nv_basic_block *b)
321
 
{
322
 
   struct nv_instruction *nvi, *mi, *next;
323
 
   int j;
324
 
   uint8_t mod;
325
 
 
326
 
   for (nvi = b->entry; nvi; nvi = next) {
327
 
      next = nvi->next;
328
 
      if (nvi->opcode == NV_OP_SUB) {
329
 
         nvi->src[1]->mod ^= NV_MOD_NEG;
330
 
         nvi->opcode = NV_OP_ADD;
331
 
      }
332
 
 
333
 
      for (j = 0; j < 3 && nvi->src[j]; ++j) {
334
 
         mi = nvi->src[j]->value->insn;
335
 
         if (!mi)
336
 
            continue;
337
 
         if (mi->def[0]->refc > 1 || mi->predicate >= 0)
338
 
            continue;
339
 
 
340
 
         if (NV_BASEOP(mi->opcode) == NV_OP_NEG) mod = NV_MOD_NEG;
341
 
         else
342
 
         if (NV_BASEOP(mi->opcode) == NV_OP_ABS) mod = NV_MOD_ABS;
343
 
         else
344
 
            continue;
345
 
         assert(!(mod & mi->src[0]->mod & NV_MOD_NEG));
346
 
 
347
 
         mod |= mi->src[0]->mod;
348
 
 
349
 
         if ((nvi->opcode == NV_OP_ABS) || (nvi->src[j]->mod & NV_MOD_ABS)) {
350
 
            /* abs neg [abs] = abs */
351
 
            mod &= ~(NV_MOD_NEG | NV_MOD_ABS);
352
 
         } else
353
 
         if ((nvi->opcode == NV_OP_NEG) && (mod & NV_MOD_NEG)) {
354
 
            /* neg as opcode and modifier on same insn cannot occur */
355
 
            /* neg neg abs = abs, neg neg = identity */
356
 
            assert(j == 0);
357
 
            if (mod & NV_MOD_ABS)
358
 
               nvi->opcode = NV_OP_ABS;
359
 
            else
360
 
               nvi->opcode = NV_OP_MOV;
361
 
            mod = 0;
362
 
         }
363
 
 
364
 
         if ((nv_op_supported_src_mods(nvi->opcode, j) & mod) != mod)
365
 
            continue;
366
 
 
367
 
         nv_reference(ctx->pc, nvi, j, mi->src[0]->value);
368
 
 
369
 
         nvi->src[j]->mod ^= mod;
370
 
      }
371
 
 
372
 
      if (nvi->opcode == NV_OP_SAT) {
373
 
         mi = nvi->src[0]->value->insn;
374
 
 
375
 
         if (mi->def[0]->refc > 1 ||
376
 
             (mi->opcode != NV_OP_ADD &&
377
 
              mi->opcode != NV_OP_MUL &&
378
 
              mi->opcode != NV_OP_MAD))
379
 
            continue;
380
 
         mi->saturate = 1;
381
 
         mi->def[0] = nvi->def[0];
382
 
         mi->def[0]->insn = mi;
383
 
         nvc0_insn_delete(nvi);
384
 
      }
385
 
   }
386
 
   DESCEND_ARBITRARY(j, nv_pass_lower_mods);
387
 
 
388
 
   return 0;
389
 
}
390
 
 
391
 
#define SRC_IS_MUL(s) ((s)->insn && (s)->insn->opcode == NV_OP_MUL)
392
 
 
393
 
static void
394
 
apply_modifiers(uint32_t *val, uint8_t type, uint8_t mod)
395
 
{
396
 
   if (mod & NV_MOD_ABS) {
397
 
      if (type == NV_TYPE_F32)
398
 
         *val &= 0x7fffffff;
399
 
      else
400
 
      if ((*val) & (1 << 31))
401
 
         *val = ~(*val) + 1;
402
 
   }
403
 
   if (mod & NV_MOD_NEG) {
404
 
      if (type == NV_TYPE_F32)
405
 
         *val ^= 0x80000000;
406
 
      else
407
 
         *val = ~(*val) + 1;
408
 
   }
409
 
   if (mod & NV_MOD_SAT) {
410
 
      union {
411
 
         float f;
412
 
         uint32_t u;
413
 
         int32_t i;
414
 
      } u;
415
 
      u.u = *val;
416
 
      if (type == NV_TYPE_F32) {
417
 
         u.f = CLAMP(u.f, -1.0f, 1.0f);
418
 
      } else
419
 
      if (type == NV_TYPE_U16) {
420
 
         u.u = MIN2(u.u, 0xffff);
421
 
      } else
422
 
      if (type == NV_TYPE_S16) {
423
 
         u.i = CLAMP(u.i, -32768, 32767);
424
 
      }
425
 
      *val = u.u;
426
 
   }
427
 
   if (mod & NV_MOD_NOT)
428
 
      *val = ~*val;
429
 
}
430
 
 
431
 
static void
432
 
constant_expression(struct nv_pc *pc, struct nv_instruction *nvi,
433
 
                    struct nv_value *src0, struct nv_value *src1)
434
 
{
435
 
   struct nv_value *val;
436
 
   union {
437
 
      float f32;
438
 
      uint32_t u32;
439
 
      int32_t s32;
440
 
   } u0, u1, u;
441
 
   ubyte type;
442
 
 
443
 
   if (!nvi->def[0])
444
 
      return;
445
 
   type = NV_OPTYPE(nvi->opcode);
446
 
 
447
 
   u.u32 = 0;
448
 
   u0.u32 = src0->reg.imm.u32;
449
 
   u1.u32 = src1->reg.imm.u32;
450
 
 
451
 
   apply_modifiers(&u0.u32, type, nvi->src[0]->mod);
452
 
   apply_modifiers(&u1.u32, type, nvi->src[1]->mod);
453
 
 
454
 
   switch (nvi->opcode) {
455
 
   case NV_OP_MAD_F32:
456
 
      if (nvi->src[2]->value->reg.file != NV_FILE_GPR)
457
 
         return;
458
 
      /* fall through */
459
 
   case NV_OP_MUL_F32:
460
 
      u.f32 = u0.f32 * u1.f32;
461
 
      break;
462
 
   case NV_OP_MUL_B32:
463
 
      u.u32 = u0.u32 * u1.u32;
464
 
      break;
465
 
   case NV_OP_ADD_F32:
466
 
      u.f32 = u0.f32 + u1.f32;
467
 
      break;
468
 
   case NV_OP_ADD_B32:
469
 
      u.u32 = u0.u32 + u1.u32;
470
 
      break;
471
 
   case NV_OP_SUB_F32:
472
 
      u.f32 = u0.f32 - u1.f32;
473
 
      break;
474
 
      /*
475
 
   case NV_OP_SUB_B32:
476
 
      u.u32 = u0.u32 - u1.u32;
477
 
      break;
478
 
      */
479
 
   default:
480
 
      return;
481
 
   }
482
 
 
483
 
   val = new_value(pc, NV_FILE_IMM, nv_type_sizeof(type));
484
 
   val->reg.imm.u32 = u.u32;
485
 
 
486
 
   nv_reference(pc, nvi, 1, NULL);
487
 
   nv_reference(pc, nvi, 0, val);
488
 
 
489
 
   if (nvi->opcode == NV_OP_MAD_F32) {
490
 
      nvi->src[1] = nvi->src[0];
491
 
      nvi->src[0] = nvi->src[2];
492
 
      nvi->src[2] = NULL;
493
 
      nvi->opcode = NV_OP_ADD_F32;
494
 
 
495
 
      if (val->reg.imm.u32 == 0) {
496
 
         nvi->src[1] = NULL;
497
 
         nvi->opcode = NV_OP_MOV;
498
 
      }
499
 
   } else {
500
 
      nvi->opcode = NV_OP_MOV;
501
 
   }
502
 
}
503
 
 
504
 
static void
505
 
constant_operand(struct nv_pc *pc,
506
 
                 struct nv_instruction *nvi, struct nv_value *val, int s)
507
 
{
508
 
   union {
509
 
      float f32;
510
 
      uint32_t u32;
511
 
      int32_t s32;
512
 
   } u;
513
 
   int shift;
514
 
   int t = s ? 0 : 1;
515
 
   uint op;
516
 
   ubyte type;
517
 
 
518
 
   if (!nvi->def[0])
519
 
      return;
520
 
   type = NV_OPTYPE(nvi->opcode);
521
 
 
522
 
   u.u32 = val->reg.imm.u32;
523
 
   apply_modifiers(&u.u32, type, nvi->src[s]->mod);
524
 
 
525
 
   if (u.u32 == 0 && NV_BASEOP(nvi->opcode) == NV_OP_MUL) {
526
 
      nvi->opcode = NV_OP_MOV;
527
 
      nv_reference(pc, nvi, t, NULL);
528
 
      if (s) {
529
 
         nvi->src[0] = nvi->src[1];
530
 
         nvi->src[1] = NULL;
531
 
      }
532
 
      return;
533
 
   }
534
 
 
535
 
   switch (nvi->opcode) {
536
 
   case NV_OP_MUL_F32:
537
 
      if (u.f32 == 1.0f || u.f32 == -1.0f) {
538
 
         if (u.f32 == -1.0f)
539
 
            nvi->src[t]->mod ^= NV_MOD_NEG;
540
 
         switch (nvi->src[t]->mod) {
541
 
         case 0: op = nvi->saturate ? NV_OP_SAT : NV_OP_MOV; break;
542
 
         case NV_MOD_NEG: op = NV_OP_NEG_F32; break;
543
 
         case NV_MOD_ABS: op = NV_OP_ABS_F32; break;
544
 
         default:
545
 
            return;
546
 
         }
547
 
         nvi->opcode = op;
548
 
         nv_reference(pc, nvi, 0, nvi->src[t]->value);
549
 
         nv_reference(pc, nvi, 1, NULL);
550
 
         nvi->src[0]->mod = 0;
551
 
      } else
552
 
      if (u.f32 == 2.0f || u.f32 == -2.0f) {
553
 
         if (u.f32 == -2.0f)
554
 
            nvi->src[t]->mod ^= NV_MOD_NEG;
555
 
         nvi->opcode = NV_OP_ADD_F32;
556
 
         nv_reference(pc, nvi, s, nvi->src[t]->value);
557
 
         nvi->src[s]->mod = nvi->src[t]->mod;
558
 
      }
559
 
      break;
560
 
   case NV_OP_ADD_F32:
561
 
      if (u.u32 == 0) {
562
 
         switch (nvi->src[t]->mod) {
563
 
         case 0: op = nvi->saturate ? NV_OP_SAT : NV_OP_MOV; break;
564
 
         case NV_MOD_NEG: op = NV_OP_NEG_F32; break;
565
 
         case NV_MOD_ABS: op = NV_OP_ABS_F32; break;
566
 
         case NV_MOD_NEG | NV_MOD_ABS:
567
 
            op = NV_OP_CVT;
568
 
            nvi->ext.cvt.s = nvi->ext.cvt.d = type;
569
 
            break;
570
 
         default:
571
 
            return;
572
 
         }
573
 
         nvi->opcode = op;
574
 
         nv_reference(pc, nvi, 0, nvi->src[t]->value);
575
 
         nv_reference(pc, nvi, 1, NULL);
576
 
         if (nvi->opcode != NV_OP_CVT)
577
 
            nvi->src[0]->mod = 0;
578
 
      }
579
 
      break;
580
 
   case NV_OP_ADD_B32:
581
 
      if (u.u32 == 0) {
582
 
         assert(nvi->src[t]->mod == 0);
583
 
         nvi->opcode = nvi->saturate ? NV_OP_CVT : NV_OP_MOV;
584
 
         nvi->ext.cvt.s = nvi->ext.cvt.d = type;
585
 
         nv_reference(pc, nvi, 0, nvi->src[t]->value);
586
 
         nv_reference(pc, nvi, 1, NULL);
587
 
      }
588
 
      break;
589
 
   case NV_OP_MUL_B32:
590
 
      /* multiplication by 0 already handled above */
591
 
      assert(nvi->src[s]->mod == 0);
592
 
      shift = ffs(u.s32) - 1;
593
 
      if (shift == 0) {
594
 
         nvi->opcode = NV_OP_MOV;
595
 
         nv_reference(pc, nvi, 0, nvi->src[t]->value);
596
 
         nv_reference(pc, nvi, 1, NULL);
597
 
      } else
598
 
      if (u.s32 > 0 && u.s32 == (1 << shift)) {
599
 
         nvi->opcode = NV_OP_SHL;
600
 
         (val = new_value(pc, NV_FILE_IMM, 4))->reg.imm.s32 = shift;
601
 
         nv_reference(pc, nvi, 0, nvi->src[t]->value);
602
 
         nv_reference(pc, nvi, 1, val);
603
 
         break;
604
 
      }
605
 
      break;
606
 
   case NV_OP_RCP:
607
 
      u.f32 = 1.0f / u.f32;
608
 
      (val = new_value(pc, NV_FILE_IMM, 4))->reg.imm.f32 = u.f32;
609
 
      nvi->opcode = NV_OP_MOV;
610
 
      assert(s == 0);
611
 
      nv_reference(pc, nvi, 0, val);
612
 
      break;
613
 
   case NV_OP_RSQ:
614
 
      u.f32 = 1.0f / sqrtf(u.f32);
615
 
      (val = new_value(pc, NV_FILE_IMM, 4))->reg.imm.f32 = u.f32;
616
 
      nvi->opcode = NV_OP_MOV;
617
 
      assert(s == 0);
618
 
      nv_reference(pc, nvi, 0, val);
619
 
      break;
620
 
   default:
621
 
      break;
622
 
   }
623
 
}
624
 
 
625
 
static void
626
 
handle_min_max(struct nv_pass *ctx, struct nv_instruction *nvi)
627
 
{
628
 
   struct nv_value *src0 = nvi->src[0]->value;
629
 
   struct nv_value *src1 = nvi->src[1]->value;
630
 
 
631
 
   if (src0 != src1 || (nvi->src[0]->mod | nvi->src[1]->mod))
632
 
      return;
633
 
   if (src0->reg.file != NV_FILE_GPR)
634
 
      return;
635
 
   nvc0_pc_replace_value(ctx->pc, nvi->def[0], src0);
636
 
   nvc0_insn_delete(nvi);
637
 
}
638
 
 
639
 
/* check if we can MUL + ADD -> MAD/FMA */
640
 
static void
641
 
handle_add_mul(struct nv_pass *ctx, struct nv_instruction *nvi)
642
 
{
643
 
   struct nv_value *src0 = nvi->src[0]->value;
644
 
   struct nv_value *src1 = nvi->src[1]->value;
645
 
   struct nv_value *src;
646
 
   int s;
647
 
   uint8_t mod[4];
648
 
 
649
 
   if (SRC_IS_MUL(src0) && src0->refc == 1) s = 0;
650
 
   else
651
 
   if (SRC_IS_MUL(src1) && src1->refc == 1) s = 1;
652
 
   else
653
 
      return;
654
 
 
655
 
   if ((src0->insn && src0->insn->bb != nvi->bb) ||
656
 
       (src1->insn && src1->insn->bb != nvi->bb))
657
 
      return;
658
 
 
659
 
   /* check for immediates from prior constant folding */
660
 
   if (src0->reg.file != NV_FILE_GPR || src1->reg.file != NV_FILE_GPR)
661
 
      return;
662
 
   src = nvi->src[s]->value;
663
 
 
664
 
   mod[0] = nvi->src[0]->mod;
665
 
   mod[1] = nvi->src[1]->mod;
666
 
   mod[2] = src->insn->src[0]->mod;
667
 
   mod[3] = src->insn->src[1]->mod;
668
 
 
669
 
   if ((mod[0] | mod[1] | mod[2] | mod[3]) & ~NV_MOD_NEG)
670
 
      return;
671
 
 
672
 
   nvi->opcode = NV_OP_MAD_F32;
673
 
 
674
 
   nv_reference(ctx->pc, nvi, s, NULL);
675
 
   nvi->src[2] = nvi->src[!s];
676
 
   nvi->src[!s] = NULL;
677
 
 
678
 
   nv_reference(ctx->pc, nvi, 0, src->insn->src[0]->value);
679
 
   nvi->src[0]->mod = mod[2] ^ mod[s];
680
 
   nv_reference(ctx->pc, nvi, 1, src->insn->src[1]->value);
681
 
   nvi->src[1]->mod = mod[3];
682
 
}
683
 
 
684
 
static int
685
 
nv_pass_algebraic_opt(struct nv_pass *ctx, struct nv_basic_block *b)
686
 
{
687
 
   struct nv_instruction *nvi, *next;
688
 
   int j;
689
 
 
690
 
   for (nvi = b->entry; nvi; nvi = next) {
691
 
      struct nv_value *src0, *src1;
692
 
      uint baseop = NV_BASEOP(nvi->opcode);
693
 
 
694
 
      next = nvi->next;
695
 
 
696
 
      src0 = nvc0_pc_find_immediate(nvi->src[0]);
697
 
      src1 = nvc0_pc_find_immediate(nvi->src[1]);
698
 
 
699
 
      if (src0 && src1) {
700
 
         constant_expression(ctx->pc, nvi, src0, src1);
701
 
      } else {
702
 
         if (src0)
703
 
            constant_operand(ctx->pc, nvi, src0, 0);
704
 
         else
705
 
         if (src1)
706
 
            constant_operand(ctx->pc, nvi, src1, 1);
707
 
      }
708
 
 
709
 
      if (baseop == NV_OP_MIN || baseop == NV_OP_MAX)
710
 
         handle_min_max(ctx, nvi);
711
 
      else
712
 
      if (nvi->opcode == NV_OP_ADD_F32)
713
 
         handle_add_mul(ctx, nvi);
714
 
   }
715
 
   DESCEND_ARBITRARY(j, nv_pass_algebraic_opt);
716
 
 
717
 
   return 0;
718
 
}
719
 
 
720
 
/* TODO: redundant store elimination */
721
 
 
722
 
struct mem_record {
723
 
   struct mem_record *next;
724
 
   struct nv_instruction *insn;
725
 
   uint32_t ofst;
726
 
   uint32_t base;
727
 
   uint32_t size;
728
 
};
729
 
 
730
 
#define MEM_RECORD_POOL_SIZE 1024
731
 
 
732
 
struct pass_reld_elim {
733
 
   struct nv_pc *pc;
734
 
 
735
 
   struct mem_record *imm;
736
 
   struct mem_record *mem_v;
737
 
   struct mem_record *mem_a;
738
 
   struct mem_record *mem_c[16];
739
 
   struct mem_record *mem_l;
740
 
 
741
 
   struct mem_record pool[MEM_RECORD_POOL_SIZE];
742
 
   int alloc;
743
 
};
744
 
 
745
 
/* Extend the load operation in @rec to also cover the data loaded by @ld.
746
 
 * The two loads may not overlap but reference adjacent memory locations.
747
 
 */
748
 
static void
749
 
combine_load(struct nv_pc *pc, struct mem_record *rec,
750
 
             struct nv_instruction *ld)
751
 
{
752
 
   struct nv_instruction *fv = rec->insn;
753
 
   struct nv_value *mem = ld->src[0]->value;
754
 
   uint32_t size = rec->size + mem->reg.size;
755
 
   int j;
756
 
   int d = rec->size / 4;
757
 
 
758
 
   assert(rec->size < 16);
759
 
   if (rec->ofst > mem->reg.address) {
760
 
      if ((size == 8 && mem->reg.address & 3) ||
761
 
          (size > 8 && mem->reg.address & 7))
762
 
         return;
763
 
      rec->ofst = mem->reg.address;
764
 
      for (j = 0; j < d; ++j)
765
 
         fv->def[mem->reg.size / 4 + j] = fv->def[j];
766
 
      d = 0;
767
 
   } else
768
 
   if ((size == 8 && rec->ofst & 3) ||
769
 
       (size > 8 && rec->ofst & 7)) {
770
 
      return;
771
 
   }
772
 
 
773
 
   for (j = 0; j < mem->reg.size / 4; ++j) {
774
 
      fv->def[d] = ld->def[j];
775
 
      fv->def[d++]->insn = fv;
776
 
   }
777
 
 
778
 
   if (fv->src[0]->value->refc > 1)
779
 
      nv_reference(pc, fv, 0, new_value_like(pc, fv->src[0]->value));
780
 
   fv->src[0]->value->reg.address = rec->ofst;
781
 
   fv->src[0]->value->reg.size = rec->size = size;
782
 
 
783
 
   nvc0_insn_delete(ld);
784
 
}
785
 
 
786
 
static void
787
 
combine_export(struct mem_record *rec, struct nv_instruction *ex)
788
 
{
789
 
 
790
 
}
791
 
 
792
 
static INLINE void
793
 
add_mem_record(struct pass_reld_elim *ctx, struct mem_record **rec,
794
 
               uint32_t base, uint32_t ofst, struct nv_instruction *nvi)
795
 
{
796
 
   struct mem_record *it = &ctx->pool[ctx->alloc++];
797
 
 
798
 
   it->next = *rec;
799
 
   *rec = it;
800
 
   it->base = base;
801
 
   it->ofst = ofst;
802
 
   it->insn = nvi;
803
 
   it->size = nvi->src[0]->value->reg.size;
804
 
}
805
 
 
806
 
/* vectorize and reuse loads from memory or of immediates */
807
 
static int
808
 
nv_pass_mem_opt(struct pass_reld_elim *ctx, struct nv_basic_block *b)
809
 
{
810
 
   struct mem_record **rec, *it;
811
 
   struct nv_instruction *ld, *next;
812
 
   struct nv_value *mem;
813
 
   uint32_t base, ofst;
814
 
   int s;
815
 
 
816
 
   for (ld = b->entry; ld; ld = next) {
817
 
      next = ld->next;
818
 
 
819
 
      if (is_cspace_load(ld)) {
820
 
         mem = ld->src[0]->value;
821
 
         rec = &ctx->mem_c[ld->src[0]->value->reg.file - NV_FILE_MEM_C(0)];
822
 
      } else
823
 
      if (ld->opcode == NV_OP_VFETCH) {
824
 
         mem = ld->src[0]->value;
825
 
         rec = &ctx->mem_a;
826
 
      } else
827
 
      if (ld->opcode == NV_OP_EXPORT) {
828
 
         mem = ld->src[0]->value;
829
 
         if (mem->reg.file != NV_FILE_MEM_V)
830
 
            continue;
831
 
         rec = &ctx->mem_v;
832
 
      } else {
833
 
         continue;
834
 
      }
835
 
      if (ld->def[0] && ld->def[0]->refc == 0)
836
 
         continue;
837
 
      ofst = mem->reg.address;
838
 
      base = (ld->indirect >= 0) ? ld->src[ld->indirect]->value->n : 0;
839
 
 
840
 
      for (it = *rec; it; it = it->next) {
841
 
         if (it->base == base &&
842
 
             ((it->ofst >> 4) == (ofst >> 4)) &&
843
 
             ((it->ofst + it->size == ofst) ||
844
 
              (it->ofst - mem->reg.size == ofst))) {
845
 
            /* only NV_OP_VFETCH can load exactly 12 bytes */
846
 
            if (ld->opcode == NV_OP_LD && it->size + mem->reg.size == 12)
847
 
               continue;
848
 
            if (it->ofst < ofst) {
849
 
               if ((it->ofst & 0xf) == 4)
850
 
                  continue;
851
 
            } else
852
 
            if ((ofst & 0xf) == 4)
853
 
               continue;
854
 
            break;
855
 
         }
856
 
      }
857
 
      if (it) {
858
 
         switch (ld->opcode) {
859
 
         case NV_OP_EXPORT: combine_export(it, ld); break;
860
 
         default:
861
 
            combine_load(ctx->pc, it, ld);
862
 
            break;
863
 
         }
864
 
      } else
865
 
      if (ctx->alloc < MEM_RECORD_POOL_SIZE) {
866
 
         add_mem_record(ctx, rec, base, ofst, ld);
867
 
      }
868
 
   }
869
 
 
870
 
   ctx->alloc = 0;
871
 
   ctx->mem_a = ctx->mem_v = ctx->mem_l = NULL;
872
 
   for (s = 0; s < 16; ++s)
873
 
      ctx->mem_c[s] = NULL;
874
 
 
875
 
   DESCEND_ARBITRARY(s, nv_pass_mem_opt);
876
 
   return 0;
877
 
}
878
 
 
879
 
static void
880
 
eliminate_store(struct mem_record *rec, struct nv_instruction *st)
881
 
{
882
 
}
883
 
 
884
 
/* elimination of redundant stores */
885
 
static int
886
 
pass_store_elim(struct pass_reld_elim *ctx, struct nv_basic_block *b)
887
 
{
888
 
   struct mem_record **rec, *it;
889
 
   struct nv_instruction *st, *next;
890
 
   struct nv_value *mem;
891
 
   uint32_t base, ofst, size;
892
 
   int s;
893
 
 
894
 
   for (st = b->entry; st; st = next) {
895
 
      next = st->next;
896
 
 
897
 
      if (st->opcode == NV_OP_ST) {
898
 
         mem = st->src[0]->value;
899
 
         rec = &ctx->mem_l;
900
 
      } else
901
 
      if (st->opcode == NV_OP_EXPORT) {
902
 
         mem = st->src[0]->value;
903
 
         if (mem->reg.file != NV_FILE_MEM_V)
904
 
            continue;
905
 
         rec = &ctx->mem_v;
906
 
      } else
907
 
      if (st->opcode == NV_OP_ST) {
908
 
         /* TODO: purge */
909
 
      }
910
 
      ofst = mem->reg.address;
911
 
      base = (st->indirect >= 0) ? st->src[st->indirect]->value->n : 0;
912
 
      size = mem->reg.size;
913
 
 
914
 
      for (it = *rec; it; it = it->next) {
915
 
         if (it->base == base &&
916
 
             (it->ofst <= ofst && (it->ofst + size) > ofst))
917
 
            break;
918
 
      }
919
 
      if (it)
920
 
         eliminate_store(it, st);
921
 
      else
922
 
         add_mem_record(ctx, rec, base, ofst, st);
923
 
   }
924
 
 
925
 
   DESCEND_ARBITRARY(s, nv_pass_mem_opt);
926
 
   return 0;
927
 
}
928
 
 
929
 
/* TODO: properly handle loads from l[] memory in the presence of stores */
930
 
static int
931
 
nv_pass_reload_elim(struct pass_reld_elim *ctx, struct nv_basic_block *b)
932
 
{
933
 
#if 0
934
 
   struct load_record **rec, *it;
935
 
   struct nv_instruction *ld, *next;
936
 
   uint64_t data[2];
937
 
   struct nv_value *val;
938
 
   int j;
939
 
 
940
 
   for (ld = b->entry; ld; ld = next) {
941
 
      next = ld->next;
942
 
      if (!ld->src[0])
943
 
         continue;
944
 
      val = ld->src[0]->value;
945
 
      rec = NULL;
946
 
 
947
 
      if (ld->opcode == NV_OP_LINTERP || ld->opcode == NV_OP_PINTERP) {
948
 
         data[0] = val->reg.id;
949
 
         data[1] = 0;
950
 
         rec = &ctx->mem_v;
951
 
      } else
952
 
      if (ld->opcode == NV_OP_LDA) {
953
 
         data[0] = val->reg.id;
954
 
         data[1] = ld->src[4] ? ld->src[4]->value->n : ~0ULL;
955
 
         if (val->reg.file >= NV_FILE_MEM_C(0) &&
956
 
             val->reg.file <= NV_FILE_MEM_C(15))
957
 
            rec = &ctx->mem_c[val->reg.file - NV_FILE_MEM_C(0)];
958
 
         else
959
 
         if (val->reg.file == NV_FILE_MEM_S)
960
 
            rec = &ctx->mem_s;
961
 
         else
962
 
         if (val->reg.file == NV_FILE_MEM_L)
963
 
            rec = &ctx->mem_l;
964
 
      } else
965
 
      if ((ld->opcode == NV_OP_MOV) && (val->reg.file == NV_FILE_IMM)) {
966
 
         data[0] = val->reg.imm.u32;
967
 
         data[1] = 0;
968
 
         rec = &ctx->imm;
969
 
      }
970
 
 
971
 
      if (!rec || !ld->def[0]->refc)
972
 
         continue;
973
 
 
974
 
      for (it = *rec; it; it = it->next)
975
 
         if (it->data[0] == data[0] && it->data[1] == data[1])
976
 
            break;
977
 
 
978
 
      if (it) {
979
 
         if (ld->def[0]->reg.id >= 0)
980
 
            it->value = ld->def[0];
981
 
         else
982
 
         if (!ld->fixed)
983
 
            nvc0_pc_replace_value(ctx->pc, ld->def[0], it->value);
984
 
      } else {
985
 
         if (ctx->alloc == LOAD_RECORD_POOL_SIZE)
986
 
            continue;
987
 
         it = &ctx->pool[ctx->alloc++];
988
 
         it->next = *rec;
989
 
         it->data[0] = data[0];
990
 
         it->data[1] = data[1];
991
 
         it->value = ld->def[0];
992
 
         *rec = it;
993
 
      }
994
 
   }
995
 
 
996
 
   ctx->imm = NULL;
997
 
   ctx->mem_s = NULL;
998
 
   ctx->mem_v = NULL;
999
 
   for (j = 0; j < 16; ++j)
1000
 
      ctx->mem_c[j] = NULL;
1001
 
   ctx->mem_l = NULL;
1002
 
   ctx->alloc = 0;
1003
 
 
1004
 
   DESCEND_ARBITRARY(j, nv_pass_reload_elim);
1005
 
#endif
1006
 
   return 0;
1007
 
}
1008
 
 
1009
 
static int
1010
 
nv_pass_tex_mask(struct nv_pass *ctx, struct nv_basic_block *b)
1011
 
{
1012
 
   int i, c, j;
1013
 
 
1014
 
   for (i = 0; i < ctx->pc->num_instructions; ++i) {
1015
 
      struct nv_instruction *nvi = &ctx->pc->instructions[i];
1016
 
      struct nv_value *def[4];
1017
 
 
1018
 
      if (!nv_is_texture_op(nvi->opcode))
1019
 
         continue;
1020
 
      nvi->tex_mask = 0;
1021
 
 
1022
 
      for (c = 0; c < 4; ++c) {
1023
 
         if (nvi->def[c]->refc)
1024
 
            nvi->tex_mask |= 1 << c;
1025
 
         def[c] = nvi->def[c];
1026
 
      }
1027
 
 
1028
 
      j = 0;
1029
 
      for (c = 0; c < 4; ++c)
1030
 
         if (nvi->tex_mask & (1 << c))
1031
 
            nvi->def[j++] = def[c];
1032
 
      for (c = 0; c < 4; ++c)
1033
 
         if (!(nvi->tex_mask & (1 << c)))
1034
 
           nvi->def[j++] = def[c];
1035
 
      assert(j == 4);
1036
 
   }
1037
 
   return 0;
1038
 
}
1039
 
 
1040
 
struct nv_pass_dce {
1041
 
   struct nv_pc *pc;
1042
 
   uint removed;
1043
 
};
1044
 
 
1045
 
static int
1046
 
nv_pass_dce(struct nv_pass_dce *ctx, struct nv_basic_block *b)
1047
 
{
1048
 
   int j;
1049
 
   struct nv_instruction *nvi, *next;
1050
 
 
1051
 
   for (nvi = b->phi ? b->phi : b->entry; nvi; nvi = next) {
1052
 
      next = nvi->next;
1053
 
 
1054
 
      if (inst_removable(nvi)) {
1055
 
         nvc0_insn_delete(nvi);
1056
 
         ++ctx->removed;
1057
 
      }
1058
 
   }
1059
 
   DESCEND_ARBITRARY(j, nv_pass_dce);
1060
 
 
1061
 
   return 0;
1062
 
}
1063
 
 
1064
 
/* Register allocation inserted ELSE blocks for all IF/ENDIF without ELSE.
1065
 
 * Returns TRUE if @bb initiates an IF/ELSE/ENDIF clause, or is an IF with
1066
 
 * BREAK and dummy ELSE block.
1067
 
 */
1068
 
static INLINE boolean
1069
 
bb_is_if_else_endif(struct nv_basic_block *bb)
1070
 
{
1071
 
   if (!bb->out[0] || !bb->out[1])
1072
 
      return FALSE;
1073
 
 
1074
 
   if (bb->out[0]->out_kind[0] == CFG_EDGE_LOOP_LEAVE) {
1075
 
      return (bb->out[0]->out[1] == bb->out[1]->out[0] &&
1076
 
              !bb->out[1]->out[1]);
1077
 
   } else {
1078
 
      return (bb->out[0]->out[0] == bb->out[1]->out[0] &&
1079
 
              !bb->out[0]->out[1] &&
1080
 
              !bb->out[1]->out[1]);
1081
 
   }
1082
 
}
1083
 
 
1084
 
/* Predicate instructions and delete any branch at the end if it is
1085
 
 * not a break from a loop.
1086
 
 */
1087
 
static void
1088
 
predicate_instructions(struct nv_pc *pc, struct nv_basic_block *b,
1089
 
                       struct nv_value *pred, uint8_t cc)
1090
 
{
1091
 
   struct nv_instruction *nvi, *prev;
1092
 
   int s;
1093
 
 
1094
 
   if (!b->entry)
1095
 
      return;
1096
 
   for (nvi = b->entry; nvi; nvi = nvi->next) {
1097
 
      prev = nvi;
1098
 
      if (inst_is_noop(nvi))
1099
 
         continue;
1100
 
      for (s = 0; nvi->src[s]; ++s);
1101
 
      assert(s < 6);
1102
 
      nvi->predicate = s;
1103
 
      nvi->cc = cc;
1104
 
      nv_reference(pc, nvi, nvi->predicate, pred);
1105
 
   }
1106
 
   if (prev->opcode == NV_OP_BRA &&
1107
 
       b->out_kind[0] != CFG_EDGE_LOOP_LEAVE &&
1108
 
       b->out_kind[1] != CFG_EDGE_LOOP_LEAVE)
1109
 
      nvc0_insn_delete(prev);
1110
 
}
1111
 
 
1112
 
static INLINE boolean
1113
 
may_predicate_insn(struct nv_instruction *nvi, struct nv_value *pred)
1114
 
{
1115
 
   if (nvi->def[0] && values_equal(nvi->def[0], pred))
1116
 
      return FALSE;
1117
 
   return nvc0_insn_is_predicateable(nvi);
1118
 
}
1119
 
 
1120
 
/* Transform IF/ELSE/ENDIF constructs into predicated instructions
1121
 
 * where feasible.
1122
 
 */
1123
 
static int
1124
 
nv_pass_flatten(struct nv_pass *ctx, struct nv_basic_block *b)
1125
 
{
1126
 
   struct nv_instruction *nvi;
1127
 
   struct nv_value *pred;
1128
 
   int k;
1129
 
   int n0, n1; /* instruction counts of outgoing blocks */
1130
 
 
1131
 
   if (bb_is_if_else_endif(b)) {
1132
 
      assert(b->exit && b->exit->opcode == NV_OP_BRA);
1133
 
 
1134
 
      assert(b->exit->predicate >= 0);
1135
 
      pred = b->exit->src[b->exit->predicate]->value;
1136
 
 
1137
 
      n1 = n0 = 0;
1138
 
      for (nvi = b->out[0]->entry; nvi; nvi = nvi->next, ++n0)
1139
 
         if (!may_predicate_insn(nvi, pred))
1140
 
            break;
1141
 
      if (!nvi) {
1142
 
         /* we're after register allocation, so there always is an ELSE block */
1143
 
         for (nvi = b->out[1]->entry; nvi; nvi = nvi->next, ++n1)
1144
 
            if (!may_predicate_insn(nvi, pred))
1145
 
               break;
1146
 
      }
1147
 
 
1148
 
      /* 12 is an arbitrary limit */
1149
 
      if (!nvi && n0 < 12 && n1 < 12) {
1150
 
         predicate_instructions(ctx->pc, b->out[0], pred, !b->exit->cc);
1151
 
         predicate_instructions(ctx->pc, b->out[1], pred, b->exit->cc);
1152
 
 
1153
 
         nvc0_insn_delete(b->exit); /* delete the branch */
1154
 
 
1155
 
         /* and a potential joinat before it */
1156
 
         if (b->exit && b->exit->opcode == NV_OP_JOINAT)
1157
 
            nvc0_insn_delete(b->exit);
1158
 
 
1159
 
         /* remove join operations at the end of the conditional */
1160
 
         k = (b->out[0]->out_kind[0] == CFG_EDGE_LOOP_LEAVE) ? 1 : 0;
1161
 
         if ((nvi = b->out[0]->out[k]->entry)) {
1162
 
            nvi->join = 0;
1163
 
            if (nvi->opcode == NV_OP_JOIN)
1164
 
               nvc0_insn_delete(nvi);
1165
 
         }
1166
 
      }
1167
 
   }
1168
 
   DESCEND_ARBITRARY(k, nv_pass_flatten);
1169
 
 
1170
 
   return 0;
1171
 
}
1172
 
 
1173
 
/* Tests instructions for equality, but independently of sources. */
1174
 
static boolean
1175
 
is_operation_equal(struct nv_instruction *a, struct nv_instruction *b)
1176
 
{
1177
 
   if (a->opcode != b->opcode)
1178
 
      return FALSE;
1179
 
   if (nv_is_texture_op(a->opcode)) {
1180
 
      if (a->ext.tex.t != b->ext.tex.t ||
1181
 
          a->ext.tex.s != b->ext.tex.s)
1182
 
         return FALSE;
1183
 
      if (a->tex_dim != b->tex_dim ||
1184
 
          a->tex_array != b->tex_array ||
1185
 
          a->tex_cube != b->tex_cube ||
1186
 
          a->tex_shadow != b->tex_shadow ||
1187
 
          a->tex_live != b->tex_live)
1188
 
         return FALSE;
1189
 
   } else
1190
 
   if (a->opcode == NV_OP_CVT) {
1191
 
      if (a->ext.cvt.s != b->ext.cvt.s ||
1192
 
          a->ext.cvt.d != b->ext.cvt.d)
1193
 
         return FALSE;
1194
 
   } else
1195
 
   if (NV_BASEOP(a->opcode) == NV_OP_SET ||
1196
 
       NV_BASEOP(a->opcode) == NV_OP_SLCT) {
1197
 
      if (a->set_cond != b->set_cond)
1198
 
         return FALSE;
1199
 
   } else
1200
 
   if (a->opcode == NV_OP_LINTERP ||
1201
 
       a->opcode == NV_OP_PINTERP) {
1202
 
      if (a->centroid != b->centroid ||
1203
 
          a->flat != b->flat)
1204
 
         return FALSE;
1205
 
   }
1206
 
   if (a->cc != b->cc)
1207
 
      return FALSE;
1208
 
   if (a->lanes != b->lanes ||
1209
 
       a->patch != b->patch ||
1210
 
       a->saturate != b->saturate)
1211
 
      return FALSE;
1212
 
   if (a->opcode == NV_OP_QUADOP) /* beware quadon ! */
1213
 
      return FALSE;
1214
 
   return TRUE;
1215
 
}
1216
 
 
1217
 
/* local common subexpression elimination, stupid O(n^2) implementation */
1218
 
static int
1219
 
nv_pass_cse(struct nv_pass *ctx, struct nv_basic_block *b)
1220
 
{
1221
 
   struct nv_instruction *ir, *ik, *next;
1222
 
   struct nv_instruction *entry = b->phi ? b->phi : b->entry;
1223
 
   int s, d;
1224
 
   unsigned int reps;
1225
 
 
1226
 
   do {
1227
 
      reps = 0;
1228
 
      for (ir = entry; ir; ir = next) {
1229
 
         next = ir->next;
1230
 
         if (ir->fixed)
1231
 
            continue;
1232
 
         for (ik = entry; ik != ir; ik = ik->next) {
1233
 
            if (!is_operation_equal(ir, ik))
1234
 
               continue;
1235
 
            if (!ir->def[0] || !ik->def[0])
1236
 
               continue;
1237
 
 
1238
 
            if (ik->indirect != ir->indirect || ik->predicate != ir->predicate)
1239
 
               continue;
1240
 
 
1241
 
            for (d = 0; d < 4; ++d) {
1242
 
               if ((ir->def[d] ? 1 : 0) != (ik->def[d] ? 1 : 0))
1243
 
                  break;
1244
 
               if (ir->def[d]) {
1245
 
                  if (!values_equal(ik->def[0], ir->def[0]))
1246
 
                     break;
1247
 
               } else {
1248
 
                  d = 4;
1249
 
                  break;
1250
 
               }
1251
 
            }
1252
 
            if (d != 4)
1253
 
               continue;
1254
 
 
1255
 
            for (s = 0; s < 5; ++s) {
1256
 
               struct nv_value *a, *b;
1257
 
 
1258
 
               if ((ir->src[s] ? 1 : 0) != (ik->src[s] ? 1 : 0))
1259
 
                  break;
1260
 
               if (!ir->src[s]) {
1261
 
                  s = 5;
1262
 
                  break;
1263
 
               }
1264
 
 
1265
 
               if (ik->src[s]->mod != ir->src[s]->mod)
1266
 
                  break;
1267
 
               a = ik->src[s]->value;
1268
 
               b = ir->src[s]->value;
1269
 
               if (a == b)
1270
 
                  continue;
1271
 
               if (a->reg.file != b->reg.file ||
1272
 
                   a->reg.id < 0 || /* this excludes memory loads/stores */
1273
 
                   a->reg.id != b->reg.id)
1274
 
                  break;
1275
 
            }
1276
 
            if (s == 5) {
1277
 
               nvc0_insn_delete(ir);
1278
 
               for (d = 0; d < 4 && ir->def[d]; ++d)
1279
 
                  nvc0_pc_replace_value(ctx->pc, ir->def[d], ik->def[d]);
1280
 
               ++reps;
1281
 
               break;
1282
 
            }
1283
 
         }
1284
 
      }
1285
 
   } while(reps);
1286
 
 
1287
 
   DESCEND_ARBITRARY(s, nv_pass_cse);
1288
 
 
1289
 
   return 0;
1290
 
}
1291
 
 
1292
 
/* Make sure all sources of an NV_OP_BIND are distinct, they need to occupy
1293
 
 * neighbouring registers. CSE might have messed this up.
1294
 
 * Just generate a MOV for each source to avoid conflicts if they're used in
1295
 
 * multiple NV_OP_BIND at different positions.
1296
 
 *
1297
 
 * Add a dummy use of the pointer source of >= 8 byte loads after the load
1298
 
 * to prevent it from being assigned a register which overlaps the load's
1299
 
 * destination, which would produce random corruptions.
1300
 
 */
1301
 
static int
1302
 
nv_pass_fixups(struct nv_pass *ctx, struct nv_basic_block *b)
1303
 
{
1304
 
   struct nv_value *val;
1305
 
   struct nv_instruction *fix, *nvi, *next;
1306
 
   int s;
1307
 
 
1308
 
   for (fix = b->entry; fix; fix = next) {
1309
 
      next = fix->next;
1310
 
 
1311
 
      if (fix->opcode == NV_OP_LD) {
1312
 
         if (fix->indirect >= 0 && fix->src[0]->value->reg.size >= 8) {
1313
 
            nvi = nv_alloc_instruction(ctx->pc, NV_OP_UNDEF);
1314
 
            nv_reference(ctx->pc, nvi, 0, fix->src[fix->indirect]->value);
1315
 
 
1316
 
            nvc0_insn_insert_after(fix, nvi);
1317
 
         }
1318
 
         continue;
1319
 
      } else
1320
 
      if (fix->opcode == NV_OP_BIND) {
1321
 
         for (s = 0; s < 4 && fix->src[s]; ++s) {
1322
 
            val = fix->src[s]->value;
1323
 
 
1324
 
            nvi = nv_alloc_instruction(ctx->pc, NV_OP_MOV);
1325
 
            nvi->def[0] = new_value_like(ctx->pc, val);
1326
 
            nvi->def[0]->insn = nvi;
1327
 
            nv_reference(ctx->pc, nvi, 0, val);
1328
 
            nv_reference(ctx->pc, fix, s, nvi->def[0]);
1329
 
 
1330
 
            nvc0_insn_insert_before(fix, nvi);
1331
 
         }
1332
 
      }
1333
 
   }
1334
 
   DESCEND_ARBITRARY(s, nv_pass_fixups);
1335
 
 
1336
 
   return 0;
1337
 
}
1338
 
 
1339
 
static int
1340
 
nv_pc_pass0(struct nv_pc *pc, struct nv_basic_block *root)
1341
 
{
1342
 
   struct pass_reld_elim *reldelim;
1343
 
   struct nv_pass pass;
1344
 
   struct nv_pass_dce dce;
1345
 
   int ret;
1346
 
 
1347
 
   pass.n = 0;
1348
 
   pass.pc = pc;
1349
 
 
1350
 
   /* Do CSE so we can just compare values by pointer in subsequent passes. */
1351
 
   pc->pass_seq++;
1352
 
   ret = nv_pass_cse(&pass, root);
1353
 
   if (ret)
1354
 
      return ret;
1355
 
 
1356
 
   /* Do this first, so we don't have to pay attention
1357
 
    * to whether sources are supported memory loads.
1358
 
    */
1359
 
   pc->pass_seq++;
1360
 
   ret = nv_pass_algebraic_opt(&pass, root);
1361
 
   if (ret)
1362
 
      return ret;
1363
 
 
1364
 
   pc->pass_seq++;
1365
 
   ret = nv_pass_lower_mods(&pass, root);
1366
 
   if (ret)
1367
 
      return ret;
1368
 
 
1369
 
   pc->pass_seq++;
1370
 
   ret = nvc0_pass_fold_loads(&pass, root);
1371
 
   if (ret)
1372
 
      return ret;
1373
 
 
1374
 
   if (pc->opt_reload_elim) {
1375
 
      reldelim = CALLOC_STRUCT(pass_reld_elim);
1376
 
      reldelim->pc = pc;
1377
 
 
1378
 
      pc->pass_seq++;
1379
 
      ret = nv_pass_reload_elim(reldelim, root);
1380
 
      if (ret) {
1381
 
         FREE(reldelim);
1382
 
         return ret;
1383
 
      }
1384
 
      memset(reldelim, 0, sizeof(struct pass_reld_elim));
1385
 
      reldelim->pc = pc;
1386
 
   }
1387
 
 
1388
 
   /* May run DCE before load-combining since that pass will clean up
1389
 
    * after itself.
1390
 
    */
1391
 
   dce.pc = pc;
1392
 
   do {
1393
 
      dce.removed = 0;
1394
 
      pc->pass_seq++;
1395
 
      ret = nv_pass_dce(&dce, root);
1396
 
      if (ret)
1397
 
         return ret;
1398
 
   } while (dce.removed);
1399
 
 
1400
 
   if (pc->opt_reload_elim) {
1401
 
      pc->pass_seq++;
1402
 
      ret = nv_pass_mem_opt(reldelim, root);
1403
 
      if (!ret) {
1404
 
         memset(reldelim, 0, sizeof(struct pass_reld_elim));
1405
 
         reldelim->pc = pc;
1406
 
 
1407
 
         pc->pass_seq++;
1408
 
         ret = nv_pass_mem_opt(reldelim, root);
1409
 
      }
1410
 
      FREE(reldelim);
1411
 
      if (ret)
1412
 
         return ret;
1413
 
   }
1414
 
 
1415
 
   ret = nv_pass_tex_mask(&pass, root);
1416
 
   if (ret)
1417
 
      return ret;
1418
 
 
1419
 
   pc->pass_seq++;
1420
 
   ret = nv_pass_fixups(&pass, root);
1421
 
 
1422
 
   return ret;
1423
 
}
1424
 
 
1425
 
int
1426
 
nvc0_pc_exec_pass0(struct nv_pc *pc)
1427
 
{
1428
 
   int i, ret;
1429
 
 
1430
 
   for (i = 0; i < pc->num_subroutines + 1; ++i)
1431
 
      if (pc->root[i] && (ret = nv_pc_pass0(pc, pc->root[i])))
1432
 
         return ret;
1433
 
   return 0;
1434
 
}