summaryrefslogtreecommitdiff
path: root/src/intel/compiler/brw_ir_vec4.h
blob: e401d8b4d1613d97d915b782f2f67b42d45f382a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
/* -*- c++ -*- */
/*
 * Copyright © 2011-2015 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#ifndef BRW_IR_VEC4_H
#define BRW_IR_VEC4_H

#include "brw_shader.h"

namespace brw {

class dst_reg;

class src_reg : public backend_reg
{
public:
   DECLARE_RALLOC_CXX_OPERATORS(src_reg)

   void init();

   src_reg(enum brw_reg_file file, int nr, const glsl_type *type);
   src_reg();
   src_reg(struct ::brw_reg reg);

   bool equals(const src_reg &r) const;
   bool negative_equals(const src_reg &r) const;

   src_reg(class vec4_visitor *v, const struct glsl_type *type);
   src_reg(class vec4_visitor *v, const struct glsl_type *type, int size);

   explicit src_reg(const dst_reg &reg);

   src_reg *reladdr;
};

static inline src_reg
retype(src_reg reg, enum brw_reg_type type)
{
   reg.type = type;
   return reg;
}

namespace detail {

static inline void
add_byte_offset(backend_reg *reg, unsigned bytes)
{
   switch (reg->file) {
      case BAD_FILE:
         break;
      case VGRF:
      case ATTR:
      case UNIFORM:
         reg->offset += bytes;
         assert(reg->offset % 16 == 0);
         break;
      case MRF: {
         const unsigned suboffset = reg->offset + bytes;
         reg->nr += suboffset / REG_SIZE;
         reg->offset = suboffset % REG_SIZE;
         assert(reg->offset % 16 == 0);
         break;
      }
      case ARF:
      case FIXED_GRF: {
         const unsigned suboffset = reg->subnr + bytes;
         reg->nr += suboffset / REG_SIZE;
         reg->subnr = suboffset % REG_SIZE;
         assert(reg->subnr % 16 == 0);
         break;
      }
      default:
         assert(bytes == 0);
   }
}

} /* namepace detail */

static inline src_reg
byte_offset(src_reg reg, unsigned bytes)
{
   detail::add_byte_offset(&reg, bytes);
   return reg;
}

static inline src_reg
offset(src_reg reg, unsigned width, unsigned delta)
{
   const unsigned stride = (reg.file == UNIFORM ? 0 : 4);
   const unsigned num_components = MAX2(width / 4 * stride, 4);
   return byte_offset(reg, num_components * type_sz(reg.type) * delta);
}

static inline src_reg
horiz_offset(src_reg reg, unsigned delta)
{
   return byte_offset(reg, delta * type_sz(reg.type));
}

/**
 * Reswizzle a given source register.
 * \sa brw_swizzle().
 */
static inline src_reg
swizzle(src_reg reg, unsigned swizzle)
{
   if (reg.file == IMM)
      reg.ud = brw_swizzle_immediate(reg.type, reg.ud, swizzle);
   else
      reg.swizzle = brw_compose_swizzle(swizzle, reg.swizzle);

   return reg;
}

static inline src_reg
negate(src_reg reg)
{
   assert(reg.file != IMM);
   reg.negate = !reg.negate;
   return reg;
}

static inline bool
is_uniform(const src_reg &reg)
{
   return (reg.file == IMM || reg.file == UNIFORM || reg.is_null()) &&
          (!reg.reladdr || is_uniform(*reg.reladdr));
}

class dst_reg : public backend_reg
{
public:
   DECLARE_RALLOC_CXX_OPERATORS(dst_reg)

   void init();

   dst_reg();
   dst_reg(enum brw_reg_file file, int nr);
   dst_reg(enum brw_reg_file file, int nr, const glsl_type *type,
           unsigned writemask);
   dst_reg(enum brw_reg_file file, int nr, brw_reg_type type,
           unsigned writemask);
   dst_reg(struct ::brw_reg reg);
   dst_reg(class vec4_visitor *v, const struct glsl_type *type);

   explicit dst_reg(const src_reg &reg);

   bool equals(const dst_reg &r) const;

   src_reg *reladdr;
};

static inline dst_reg
retype(dst_reg reg, enum brw_reg_type type)
{
   reg.type = type;
   return reg;
}

static inline dst_reg
byte_offset(dst_reg reg, unsigned bytes)
{
   detail::add_byte_offset(&reg, bytes);
   return reg;
}

static inline dst_reg
offset(dst_reg reg, unsigned width, unsigned delta)
{
   const unsigned stride = (reg.file == UNIFORM ? 0 : 4);
   const unsigned num_components = MAX2(width / 4 * stride, 4);
   return byte_offset(reg, num_components * type_sz(reg.type) * delta);
}

static inline dst_reg
horiz_offset(const dst_reg &reg, unsigned delta)
{
   if (is_uniform(src_reg(reg)))
      return reg;
   else
      return byte_offset(reg, delta * type_sz(reg.type));
}

static inline dst_reg
writemask(dst_reg reg, unsigned mask)
{
   assert(reg.file != IMM);
   assert((reg.writemask & mask) != 0);
   reg.writemask &= mask;
   return reg;
}

/**
 * Return an integer identifying the discrete address space a register is
 * contained in.  A register is by definition fully contained in the single
 * reg_space it belongs to, so two registers with different reg_space ids are
 * guaranteed not to overlap.  Most register files are a single reg_space of
 * its own, only the VGRF file is composed of multiple discrete address
 * spaces, one for each VGRF allocation.
 */
static inline uint32_t
reg_space(const backend_reg &r)
{
   return r.file << 16 | (r.file == VGRF ? r.nr : 0);
}

/**
 * Return the base offset in bytes of a register relative to the start of its
 * reg_space().
 */
static inline unsigned
reg_offset(const backend_reg &r)
{
   return (r.file == VGRF || r.file == IMM ? 0 : r.nr) *
          (r.file == UNIFORM ? 16 : REG_SIZE) + r.offset +
          (r.file == ARF || r.file == FIXED_GRF ? r.subnr : 0);
}

/**
 * Return whether the register region starting at \p r and spanning \p dr
 * bytes could potentially overlap the register region starting at \p s and
 * spanning \p ds bytes.
 */
static inline bool
regions_overlap(const backend_reg &r, unsigned dr,
                const backend_reg &s, unsigned ds)
{
   if (r.file == MRF && (r.nr & BRW_MRF_COMPR4)) {
      /* COMPR4 regions are translated by the hardware during decompression
       * into two separate half-regions 4 MRFs apart from each other.
       */
      backend_reg t0 = r;
      t0.nr &= ~BRW_MRF_COMPR4;
      backend_reg t1 = t0;
      t1.offset += 4 * REG_SIZE;
      return regions_overlap(t0, dr / 2, s, ds) ||
             regions_overlap(t1, dr / 2, s, ds);

   } else if (s.file == MRF && (s.nr & BRW_MRF_COMPR4)) {
      return regions_overlap(s, ds, r, dr);

   } else {
      return reg_space(r) == reg_space(s) &&
             !(reg_offset(r) + dr <= reg_offset(s) ||
               reg_offset(s) + ds <= reg_offset(r));
   }
}

class vec4_instruction : public backend_instruction {
public:
   DECLARE_RALLOC_CXX_OPERATORS(vec4_instruction)

   vec4_instruction(enum opcode opcode,
                    const dst_reg &dst = dst_reg(),
                    const src_reg &src0 = src_reg(),
                    const src_reg &src1 = src_reg(),
                    const src_reg &src2 = src_reg());

   dst_reg dst;
   src_reg src[3];

   enum brw_urb_write_flags urb_write_flags;

   unsigned sol_binding; /**< gen6: SOL binding table index */
   bool sol_final_write; /**< gen6: send commit message */
   unsigned sol_vertex; /**< gen6: used for setting dst index in SVB header */

   bool is_send_from_grf();
   unsigned size_read(unsigned arg) const;
   bool can_reswizzle(const struct gen_device_info *devinfo, int dst_writemask,
                      int swizzle, int swizzle_mask);
   void reswizzle(int dst_writemask, int swizzle);
   bool can_do_source_mods(const struct gen_device_info *devinfo);
   bool can_do_writemask(const struct gen_device_info *devinfo);
   bool can_change_types() const;
   bool has_source_and_destination_hazard() const;

   bool is_align1_partial_write()
   {
      return opcode == VEC4_OPCODE_SET_LOW_32BIT ||
             opcode == VEC4_OPCODE_SET_HIGH_32BIT;
   }

   bool reads_flag()
   {
      return predicate || opcode == VS_OPCODE_UNPACK_FLAGS_SIMD4X2;
   }

   bool reads_flag(unsigned c)
   {
      if (opcode == VS_OPCODE_UNPACK_FLAGS_SIMD4X2)
         return true;

      switch (predicate) {
      case BRW_PREDICATE_NONE:
         return false;
      case BRW_PREDICATE_ALIGN16_REPLICATE_X:
         return c == 0;
      case BRW_PREDICATE_ALIGN16_REPLICATE_Y:
         return c == 1;
      case BRW_PREDICATE_ALIGN16_REPLICATE_Z:
         return c == 2;
      case BRW_PREDICATE_ALIGN16_REPLICATE_W:
         return c == 3;
      default:
         return true;
      }
   }

   bool writes_flag()
   {
      return (conditional_mod && (opcode != BRW_OPCODE_SEL &&
                                  opcode != BRW_OPCODE_CSEL &&
                                  opcode != BRW_OPCODE_IF &&
                                  opcode != BRW_OPCODE_WHILE));
   }

   bool reads_g0_implicitly() const
   {
      switch (opcode) {
      case SHADER_OPCODE_TEX:
      case SHADER_OPCODE_TXL:
      case SHADER_OPCODE_TXD:
      case SHADER_OPCODE_TXF:
      case SHADER_OPCODE_TXF_CMS_W:
      case SHADER_OPCODE_TXF_CMS:
      case SHADER_OPCODE_TXF_MCS:
      case SHADER_OPCODE_TXS:
      case SHADER_OPCODE_TG4:
      case SHADER_OPCODE_TG4_OFFSET:
      case SHADER_OPCODE_SAMPLEINFO:
      case VS_OPCODE_PULL_CONSTANT_LOAD:
      case GS_OPCODE_SET_PRIMITIVE_ID:
      case GS_OPCODE_GET_INSTANCE_ID:
      case SHADER_OPCODE_GEN4_SCRATCH_READ:
      case SHADER_OPCODE_GEN4_SCRATCH_WRITE:
         return true;
      default:
         return false;
      }
   }
};

/**
 * Make the execution of \p inst dependent on the evaluation of a possibly
 * inverted predicate.
 */
inline vec4_instruction *
set_predicate_inv(enum brw_predicate pred, bool inverse,
                  vec4_instruction *inst)
{
   inst->predicate = pred;
   inst->predicate_inverse = inverse;
   return inst;
}

/**
 * Make the execution of \p inst dependent on the evaluation of a predicate.
 */
inline vec4_instruction *
set_predicate(enum brw_predicate pred, vec4_instruction *inst)
{
   return set_predicate_inv(pred, false, inst);
}

/**
 * Write the result of evaluating the condition given by \p mod to a flag
 * register.
 */
inline vec4_instruction *
set_condmod(enum brw_conditional_mod mod, vec4_instruction *inst)
{
   inst->conditional_mod = mod;
   return inst;
}

/**
 * Clamp the result of \p inst to the saturation range of its destination
 * datatype.
 */
inline vec4_instruction *
set_saturate(bool saturate, vec4_instruction *inst)
{
   inst->saturate = saturate;
   return inst;
}

/**
 * Return the number of dataflow registers written by the instruction (either
 * fully or partially) counted from 'floor(reg_offset(inst->dst) /
 * register_size)'.  The somewhat arbitrary register size unit is 16B for the
 * UNIFORM and IMM files and 32B for all other files.
 */
inline unsigned
regs_written(const vec4_instruction *inst)
{
   assert(inst->dst.file != UNIFORM && inst->dst.file != IMM);
   return DIV_ROUND_UP(reg_offset(inst->dst) % REG_SIZE + inst->size_written,
                       REG_SIZE);
}

/**
 * Return the number of dataflow registers read by the instruction (either
 * fully or partially) counted from 'floor(reg_offset(inst->src[i]) /
 * register_size)'.  The somewhat arbitrary register size unit is 16B for the
 * UNIFORM and IMM files and 32B for all other files.
 */
inline unsigned
regs_read(const vec4_instruction *inst, unsigned i)
{
   const unsigned reg_size =
      inst->src[i].file == UNIFORM || inst->src[i].file == IMM ? 16 : REG_SIZE;
   return DIV_ROUND_UP(reg_offset(inst->src[i]) % reg_size + inst->size_read(i),
                       reg_size);
}

static inline enum brw_reg_type
get_exec_type(const vec4_instruction *inst)
{
   enum brw_reg_type exec_type = BRW_REGISTER_TYPE_B;

   for (int i = 0; i < 3; i++) {
      if (inst->src[i].file != BAD_FILE) {
         const brw_reg_type t = get_exec_type(brw_reg_type(inst->src[i].type));
         if (type_sz(t) > type_sz(exec_type))
            exec_type = t;
         else if (type_sz(t) == type_sz(exec_type) &&
                  brw_reg_type_is_floating_point(t))
            exec_type = t;
      }
   }

   if (exec_type == BRW_REGISTER_TYPE_B)
      exec_type = inst->dst.type;

   /* TODO: We need to handle half-float conversions. */
   assert(exec_type != BRW_REGISTER_TYPE_HF ||
          inst->dst.type == BRW_REGISTER_TYPE_HF);
   assert(exec_type != BRW_REGISTER_TYPE_B);

   return exec_type;
}

static inline unsigned
get_exec_type_size(const vec4_instruction *inst)
{
   return type_sz(get_exec_type(inst));
}

} /* namespace brw */

#endif