Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 1
/*
2
 * Mesa 3-D graphics library
3
 *
4
 * Copyright (C) 2012-2013 LunarG, Inc.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the "Software"),
8
 * to deal in the Software without restriction, including without limitation
9
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
 * and/or sell copies of the Software, and to permit persons to whom the
11
 * Software is furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included
14
 * in all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
 * DEALINGS IN THE SOFTWARE.
23
 *
24
 * Authors:
25
 *    Chia-I Wu 
26
 */
27
 
28
#include "pipe/p_shader_tokens.h"
29
#include "toy_compiler.h"
30
#include "toy_tgsi.h"
31
#include "toy_helpers.h"
32
#include "toy_legalize.h"
33
 
34
/**
35
 * Lower an instruction to BRW_OPCODE_SEND(C).
36
 */
37
void
38
toy_compiler_lower_to_send(struct toy_compiler *tc, struct toy_inst *inst,
39
                           bool sendc, unsigned sfid)
40
{
41
   assert(inst->opcode >= 128);
42
 
43
   inst->opcode = (sendc) ? BRW_OPCODE_SENDC : BRW_OPCODE_SEND;
44
 
45
   /* thread control is reserved */
46
   assert(inst->thread_ctrl == 0);
47
 
48
   assert(inst->cond_modifier == BRW_CONDITIONAL_NONE);
49
   inst->cond_modifier = sfid;
50
}
51
 
52
static int
53
math_op_to_func(unsigned opcode)
54
{
55
   switch (opcode) {
56
   case TOY_OPCODE_INV:    return BRW_MATH_FUNCTION_INV;
57
   case TOY_OPCODE_LOG:    return BRW_MATH_FUNCTION_LOG;
58
   case TOY_OPCODE_EXP:    return BRW_MATH_FUNCTION_EXP;
59
   case TOY_OPCODE_SQRT:   return BRW_MATH_FUNCTION_SQRT;
60
   case TOY_OPCODE_RSQ:    return BRW_MATH_FUNCTION_RSQ;
61
   case TOY_OPCODE_SIN:    return BRW_MATH_FUNCTION_SIN;
62
   case TOY_OPCODE_COS:    return BRW_MATH_FUNCTION_COS;
63
   case TOY_OPCODE_FDIV:   return BRW_MATH_FUNCTION_FDIV;
64
   case TOY_OPCODE_POW:    return BRW_MATH_FUNCTION_POW;
65
   case TOY_OPCODE_INT_DIV_QUOTIENT:   return BRW_MATH_FUNCTION_INT_DIV_QUOTIENT;
66
   case TOY_OPCODE_INT_DIV_REMAINDER:  return BRW_MATH_FUNCTION_INT_DIV_REMAINDER;
67
   default:
68
       assert(!"unknown math opcode");
69
       return -1;
70
   }
71
}
72
 
73
/**
74
 * Lower virtual math opcodes to BRW_OPCODE_MATH.
75
 */
76
void
77
toy_compiler_lower_math(struct toy_compiler *tc, struct toy_inst *inst)
78
{
79
   struct toy_dst tmp;
80
   int i;
81
 
82
   /* see commit 250770b74d33bb8625c780a74a89477af033d13a */
83
   for (i = 0; i < Elements(inst->src); i++) {
84
      if (tsrc_is_null(inst->src[i]))
85
         break;
86
 
87
      /* no swizzling in align1 */
88
      /* XXX how about source modifiers? */
89
      if (toy_file_is_virtual(inst->src[i].file) &&
90
          !tsrc_is_swizzled(inst->src[i]) &&
91
          !inst->src[i].absolute &&
92
          !inst->src[i].negate)
93
         continue;
94
 
95
      tmp = tdst_type(tc_alloc_tmp(tc), inst->src[i].type);
96
      tc_MOV(tc, tmp, inst->src[i]);
97
      inst->src[i] = tsrc_from(tmp);
98
   }
99
 
100
   /* FC[0:3] */
101
   assert(inst->cond_modifier == BRW_CONDITIONAL_NONE);
102
   inst->cond_modifier = math_op_to_func(inst->opcode);
103
   /* FC[4:5] */
104
   assert(inst->thread_ctrl == 0);
105
   inst->thread_ctrl = 0;
106
 
107
   inst->opcode = BRW_OPCODE_MATH;
108
   tc_move_inst(tc, inst);
109
 
110
   /* no writemask in align1 */
111
   if (inst->dst.writemask != TOY_WRITEMASK_XYZW) {
112
      struct toy_dst dst = inst->dst;
113
      struct toy_inst *inst2;
114
 
115
      tmp = tc_alloc_tmp(tc);
116
      tmp.type = inst->dst.type;
117
      inst->dst = tmp;
118
 
119
      inst2 = tc_MOV(tc, dst, tsrc_from(tmp));
120
      inst2->pred_ctrl = inst->pred_ctrl;
121
   }
122
}
123
 
124
static uint32_t
125
absolute_imm(uint32_t imm32, enum toy_type type)
126
{
127
   union fi val = { .ui = imm32 };
128
 
129
   switch (type) {
130
   case TOY_TYPE_F:
131
      val.f = fabs(val.f);
132
      break;
133
   case TOY_TYPE_D:
134
      if (val.i < 0)
135
         val.i = -val.i;
136
      break;
137
   case TOY_TYPE_W:
138
      if ((int16_t) (val.ui & 0xffff) < 0)
139
         val.i = -((int16_t) (val.ui & 0xffff));
140
      break;
141
   case TOY_TYPE_V:
142
      assert(!"cannot take absoulte of immediates of type V");
143
      break;
144
   default:
145
      break;
146
   }
147
 
148
   return val.ui;
149
}
150
 
151
static uint32_t
152
negate_imm(uint32_t imm32, enum toy_type type)
153
{
154
   union fi val = { .ui = imm32 };
155
 
156
   switch (type) {
157
   case TOY_TYPE_F:
158
      val.f = -val.f;
159
      break;
160
   case TOY_TYPE_D:
161
   case TOY_TYPE_UD:
162
      val.i = -val.i;
163
      break;
164
   case TOY_TYPE_W:
165
   case TOY_TYPE_UW:
166
      val.i = -((int16_t) (val.ui & 0xffff));
167
      break;
168
   default:
169
      assert(!"negate immediate of unknown type");
170
      break;
171
   }
172
 
173
   return val.ui;
174
}
175
 
176
static void
177
validate_imm(struct toy_compiler *tc, struct toy_inst *inst)
178
{
179
   bool move_inst = false;
180
   int i;
181
 
182
   for (i = 0; i < Elements(inst->src); i++) {
183
      struct toy_dst tmp;
184
 
185
      if (tsrc_is_null(inst->src[i]))
186
         break;
187
 
188
      if (inst->src[i].file != TOY_FILE_IMM)
189
         continue;
190
 
191
      if (inst->src[i].absolute) {
192
         inst->src[i].val32 =
193
            absolute_imm(inst->src[i].val32, inst->src[i].type);
194
         inst->src[i].absolute = false;
195
      }
196
 
197
      if (inst->src[i].negate) {
198
         inst->src[i].val32 =
199
            negate_imm(inst->src[i].val32, inst->src[i].type);
200
         inst->src[i].negate = false;
201
      }
202
 
203
      /* this is the last operand */
204
      if (i + 1 == Elements(inst->src) || tsrc_is_null(inst->src[i + 1]))
205
         break;
206
 
207
      /* need to use a temp if this imm is not the last operand */
208
      /* TODO we should simply swap the operands if the op is commutative */
209
      tmp = tc_alloc_tmp(tc);
210
      tmp = tdst_type(tmp, inst->src[i].type);
211
      tc_MOV(tc, tmp, inst->src[i]);
212
      inst->src[i] = tsrc_from(tmp);
213
 
214
      move_inst = true;
215
   }
216
 
217
   if (move_inst)
218
      tc_move_inst(tc, inst);
219
}
220
 
221
static void
222
lower_opcode_mul(struct toy_compiler *tc, struct toy_inst *inst)
223
{
224
   const enum toy_type inst_type = inst->dst.type;
225
   const struct toy_dst acc0 =
226
      tdst_type(tdst(TOY_FILE_ARF, BRW_ARF_ACCUMULATOR, 0), inst_type);
227
   struct toy_inst *inst2;
228
 
229
   /* only need to take care of integer multiplications */
230
   if (inst_type != TOY_TYPE_UD && inst_type != TOY_TYPE_D)
231
      return;
232
 
233
   /* acc0 = (src0 & 0x0000ffff) * src1 */
234
   tc_MUL(tc, acc0, inst->src[0], inst->src[1]);
235
 
236
   /* acc0 = (src0 & 0xffff0000) * src1 + acc0 */
237
   inst2 = tc_add2(tc, BRW_OPCODE_MACH, tdst_type(tdst_null(), inst_type),
238
         inst->src[0], inst->src[1]);
239
   inst2->acc_wr_ctrl = true;
240
 
241
   /* dst = acc0 & 0xffffffff */
242
   tc_MOV(tc, inst->dst, tsrc_from(acc0));
243
 
244
   tc_discard_inst(tc, inst);
245
}
246
 
247
static void
248
lower_opcode_mac(struct toy_compiler *tc, struct toy_inst *inst)
249
{
250
   const enum toy_type inst_type = inst->dst.type;
251
 
252
   if (inst_type != TOY_TYPE_UD && inst_type != TOY_TYPE_D) {
253
      const struct toy_dst acc0 = tdst(TOY_FILE_ARF, BRW_ARF_ACCUMULATOR, 0);
254
 
255
      tc_MOV(tc, acc0, inst->src[2]);
256
      inst->src[2] = tsrc_null();
257
      tc_move_inst(tc, inst);
258
   }
259
   else {
260
      struct toy_dst tmp = tdst_type(tc_alloc_tmp(tc), inst_type);
261
      struct toy_inst *inst2;
262
 
263
      inst2 = tc_MUL(tc, tmp, inst->src[0], inst->src[1]);
264
      lower_opcode_mul(tc, inst2);
265
 
266
      tc_ADD(tc, inst->dst, tsrc_from(tmp), inst->src[2]);
267
 
268
      tc_discard_inst(tc, inst);
269
   }
270
}
271
 
272
/**
273
 * Legalize the instructions for register allocation.
274
 */
275
void
276
toy_compiler_legalize_for_ra(struct toy_compiler *tc)
277
{
278
   struct toy_inst *inst;
279
 
280
   tc_head(tc);
281
   while ((inst = tc_next(tc)) != NULL) {
282
      switch (inst->opcode) {
283
      case BRW_OPCODE_MAC:
284
         lower_opcode_mac(tc, inst);
285
         break;
286
      case BRW_OPCODE_MAD:
287
         /* TODO operands must be floats */
288
         break;
289
      case BRW_OPCODE_MUL:
290
         lower_opcode_mul(tc, inst);
291
         break;
292
      default:
293
         if (inst->opcode > TOY_OPCODE_LAST_HW)
294
            tc_fail(tc, "internal opcodes not lowered");
295
      }
296
   }
297
 
298
   /* loop again as the previous pass may add new instructions */
299
   tc_head(tc);
300
   while ((inst = tc_next(tc)) != NULL) {
301
      validate_imm(tc, inst);
302
   }
303
}
304
 
305
static void
306
patch_while_jip(struct toy_compiler *tc, struct toy_inst *inst)
307
{
308
   struct toy_inst *inst2;
309
   int nest_level, dist;
310
 
311
   nest_level = 0;
312
   dist = -1;
313
 
314
   /* search backward */
315
   LIST_FOR_EACH_ENTRY_FROM_REV(inst2, inst->list.prev,
316
         &tc->instructions, list) {
317
      if (inst2->marker) {
318
         if (inst2->opcode == BRW_OPCODE_DO) {
319
            if (nest_level) {
320
               nest_level--;
321
            }
322
            else {
323
               /* the following instruction */
324
               dist++;
325
               break;
326
            }
327
         }
328
 
329
         continue;
330
      }
331
 
332
      if (inst2->opcode == BRW_OPCODE_WHILE)
333
         nest_level++;
334
 
335
      dist--;
336
   }
337
 
338
   if (tc->dev->gen >= ILO_GEN(7))
339
      inst->src[1] = tsrc_imm_w(dist * 2);
340
   else
341
      inst->dst = tdst_imm_w(dist * 2);
342
}
343
 
344
static void
345
patch_if_else_jip(struct toy_compiler *tc, struct toy_inst *inst)
346
{
347
   struct toy_inst *inst2;
348
   int nest_level, dist;
349
   int jip, uip;
350
 
351
   nest_level = 0;
352
   dist = 1;
353
   jip = 0;
354
   uip = 0;
355
 
356
   /* search forward */
357
   LIST_FOR_EACH_ENTRY_FROM(inst2, inst->list.next, &tc->instructions, list) {
358
      if (inst2->marker)
359
         continue;
360
 
361
      if (inst2->opcode == BRW_OPCODE_ENDIF) {
362
         if (nest_level) {
363
            nest_level--;
364
         }
365
         else {
366
            uip = dist * 2;
367
            if (!jip)
368
               jip = uip;
369
            break;
370
         }
371
      }
372
      else if (inst2->opcode == BRW_OPCODE_ELSE &&
373
               inst->opcode == BRW_OPCODE_IF) {
374
         if (!nest_level) {
375
            /* the following instruction */
376
            jip = (dist + 1) * 2;
377
 
378
            if (tc->dev->gen == ILO_GEN(6)) {
379
               uip = jip;
380
               break;
381
            }
382
         }
383
      }
384
      else if (inst2->opcode == BRW_OPCODE_IF) {
385
         nest_level++;
386
      }
387
 
388
      dist++;
389
   }
390
 
391
   if (tc->dev->gen >= ILO_GEN(7)) {
392
      /* what should the type be? */
393
      inst->dst.type = TOY_TYPE_D;
394
      inst->src[0].type = TOY_TYPE_D;
395
      inst->src[1] = tsrc_imm_d(uip << 16 | jip);
396
   }
397
   else {
398
      inst->dst = tdst_imm_w(jip);
399
   }
400
 
401
   inst->thread_ctrl = BRW_THREAD_SWITCH;
402
}
403
 
404
static void
405
patch_endif_jip(struct toy_compiler *tc, struct toy_inst *inst)
406
{
407
   struct toy_inst *inst2;
408
   bool found = false;
409
   int dist = 1;
410
 
411
   /* search forward for instructions that may enable channels */
412
   LIST_FOR_EACH_ENTRY_FROM(inst2, inst->list.next, &tc->instructions, list) {
413
      if (inst2->marker)
414
         continue;
415
 
416
      switch (inst2->opcode) {
417
      case BRW_OPCODE_ENDIF:
418
      case BRW_OPCODE_ELSE:
419
      case BRW_OPCODE_WHILE:
420
         found = true;
421
         break;
422
      default:
423
         break;
424
      }
425
 
426
      if (found)
427
         break;
428
 
429
      dist++;
430
   }
431
 
432
   /* should we set dist to (dist - 1) or 1? */
433
   if (!found)
434
      dist = 1;
435
 
436
   if (tc->dev->gen >= ILO_GEN(7))
437
      inst->src[1] = tsrc_imm_w(dist * 2);
438
   else
439
      inst->dst = tdst_imm_w(dist * 2);
440
 
441
   inst->thread_ctrl = BRW_THREAD_SWITCH;
442
}
443
 
444
static void
445
patch_break_continue_jip(struct toy_compiler *tc, struct toy_inst *inst)
446
{
447
   struct toy_inst *inst2, *inst3;
448
   int nest_level, dist, jip, uip;
449
 
450
   nest_level = 0;
451
   dist = 1;
452
   jip = 1 * 2;
453
   uip = 1 * 2;
454
 
455
   /* search forward */
456
   LIST_FOR_EACH_ENTRY_FROM(inst2, inst->list.next, &tc->instructions, list) {
457
      if (inst2->marker) {
458
         if (inst2->opcode == BRW_OPCODE_DO)
459
            nest_level++;
460
         continue;
461
      }
462
 
463
      if (inst2->opcode == BRW_OPCODE_ELSE ||
464
          inst2->opcode == BRW_OPCODE_ENDIF ||
465
          inst2->opcode == BRW_OPCODE_WHILE) {
466
         jip = dist * 2;
467
         break;
468
      }
469
 
470
      dist++;
471
   }
472
 
473
   /* go on to determine uip */
474
   inst3 = inst2;
475
   LIST_FOR_EACH_ENTRY_FROM(inst2, &inst3->list, &tc->instructions, list) {
476
      if (inst2->marker) {
477
         if (inst2->opcode == BRW_OPCODE_DO)
478
            nest_level++;
479
         continue;
480
      }
481
 
482
      if (inst2->opcode == BRW_OPCODE_WHILE) {
483
         if (nest_level) {
484
            nest_level--;
485
         }
486
         else {
487
            /* the following instruction */
488
            if (tc->dev->gen == ILO_GEN(6) && inst->opcode == BRW_OPCODE_BREAK)
489
               dist++;
490
 
491
            uip = dist * 2;
492
            break;
493
         }
494
      }
495
 
496
      dist++;
497
   }
498
 
499
   /* should the type be D or W? */
500
   inst->dst.type = TOY_TYPE_D;
501
   inst->src[0].type = TOY_TYPE_D;
502
   inst->src[1] = tsrc_imm_d(uip << 16 | jip);
503
}
504
 
505
/**
506
 * Legalize the instructions for assembling.
507
 */
508
void
509
toy_compiler_legalize_for_asm(struct toy_compiler *tc)
510
{
511
   struct toy_inst *inst;
512
   int pc = 0;
513
 
514
   tc_head(tc);
515
   while ((inst = tc_next(tc)) != NULL) {
516
      int i;
517
 
518
      pc++;
519
 
520
      /*
521
       * From the Sandy Bridge PRM, volume 4 part 2, page 112:
522
       *
523
       *     "Specifically, for instructions with a single source, it only
524
       *      uses the first source operand . In this case, the second
525
       *      source operand  must be set to null and also with the same
526
       *      type as the first source operand .  It is a special case
527
       *      when  is an immediate, as an immediate  uses DW3 of
528
       *      the instruction word, which is normally used by .  In this
529
       *      case,  must be programmed with register file ARF and the
530
       *      same data type as ."
531
       *
532
       * Since we already fill unused operands with null, we only need to take
533
       * care of the type.
534
       */
535
      if (tsrc_is_null(inst->src[1]))
536
         inst->src[1].type = inst->src[0].type;
537
 
538
      switch (inst->opcode) {
539
      case BRW_OPCODE_MATH:
540
         /* math does not support align16 nor exec_size > 8 */
541
         inst->access_mode = BRW_ALIGN_1;
542
 
543
         if (inst->exec_size == BRW_EXECUTE_16) {
544
            /*
545
             * From the Ivy Bridge PRM, volume 4 part 3, page 192:
546
             *
547
             *     "INT DIV function does not support SIMD16."
548
             */
549
            if (tc->dev->gen < ILO_GEN(7) ||
550
                inst->cond_modifier == BRW_MATH_FUNCTION_INT_DIV_QUOTIENT ||
551
                inst->cond_modifier == BRW_MATH_FUNCTION_INT_DIV_REMAINDER) {
552
               struct toy_inst *inst2;
553
 
554
               inst->exec_size = BRW_EXECUTE_8;
555
               inst->qtr_ctrl = GEN6_COMPRESSION_1Q;
556
 
557
               inst2 = tc_duplicate_inst(tc, inst);
558
               inst2->qtr_ctrl = GEN6_COMPRESSION_2Q;
559
               inst2->dst = tdst_offset(inst2->dst, 1, 0);
560
               inst2->src[0] = tsrc_offset(inst2->src[0], 1, 0);
561
               if (!tsrc_is_null(inst2->src[1]))
562
                  inst2->src[1] = tsrc_offset(inst2->src[1], 1, 0);
563
 
564
               pc++;
565
            }
566
         }
567
         break;
568
      case BRW_OPCODE_IF:
569
         if (tc->dev->gen >= ILO_GEN(7) &&
570
             inst->cond_modifier != BRW_CONDITIONAL_NONE) {
571
            struct toy_inst *inst2;
572
 
573
            inst2 = tc_duplicate_inst(tc, inst);
574
 
575
            /* replace the original IF by CMP */
576
            inst->opcode = BRW_OPCODE_CMP;
577
 
578
            /* predicate control instead of condition modifier */
579
            inst2->dst = tdst_null();
580
            inst2->src[0] = tsrc_null();
581
            inst2->src[1] = tsrc_null();
582
            inst2->cond_modifier = BRW_CONDITIONAL_NONE;
583
            inst2->pred_ctrl = BRW_PREDICATE_NORMAL;
584
 
585
            pc++;
586
         }
587
         break;
588
      default:
589
         break;
590
      }
591
 
592
      /* MRF to GRF */
593
      if (tc->dev->gen >= ILO_GEN(7)) {
594
         for (i = 0; i < Elements(inst->src); i++) {
595
            if (inst->src[i].file != TOY_FILE_MRF)
596
               continue;
597
            else if (tsrc_is_null(inst->src[i]))
598
               break;
599
 
600
            inst->src[i].file = TOY_FILE_GRF;
601
         }
602
 
603
         if (inst->dst.file == TOY_FILE_MRF)
604
            inst->dst.file = TOY_FILE_GRF;
605
      }
606
   }
607
 
608
   tc->num_instructions = pc;
609
 
610
   /* set JIP/UIP */
611
   tc_head(tc);
612
   while ((inst = tc_next(tc)) != NULL) {
613
      switch (inst->opcode) {
614
      case BRW_OPCODE_IF:
615
      case BRW_OPCODE_ELSE:
616
         patch_if_else_jip(tc, inst);
617
         break;
618
      case BRW_OPCODE_ENDIF:
619
         patch_endif_jip(tc, inst);
620
         break;
621
      case BRW_OPCODE_WHILE:
622
         patch_while_jip(tc, inst);
623
         break;
624
      case BRW_OPCODE_BREAK:
625
      case BRW_OPCODE_CONTINUE:
626
         patch_break_continue_jip(tc, inst);
627
         break;
628
      default:
629
         break;
630
      }
631
   }
632
}