Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 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 GEN6_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) ? GEN6_OPCODE_SENDC : GEN6_OPCODE_SEND;
44
 
45
   /* thread control is reserved */
46
   assert(inst->thread_ctrl == 0);
47
 
48
   assert(inst->cond_modifier == GEN6_COND_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 GEN6_MATH_INV;
57
   case TOY_OPCODE_LOG:    return GEN6_MATH_LOG;
58
   case TOY_OPCODE_EXP:    return GEN6_MATH_EXP;
59
   case TOY_OPCODE_SQRT:   return GEN6_MATH_SQRT;
60
   case TOY_OPCODE_RSQ:    return GEN6_MATH_RSQ;
61
   case TOY_OPCODE_SIN:    return GEN6_MATH_SIN;
62
   case TOY_OPCODE_COS:    return GEN6_MATH_COS;
63
   case TOY_OPCODE_FDIV:   return GEN6_MATH_FDIV;
64
   case TOY_OPCODE_POW:    return GEN6_MATH_POW;
65
   case TOY_OPCODE_INT_DIV_QUOTIENT:   return GEN6_MATH_INT_DIV_QUOTIENT;
66
   case TOY_OPCODE_INT_DIV_REMAINDER:  return GEN6_MATH_INT_DIV_REMAINDER;
67
   default:
68
       assert(!"unknown math opcode");
69
       return -1;
70
   }
71
}
72
 
73
/**
74
 * Lower virtual math opcodes to GEN6_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 == GEN6_COND_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 = GEN6_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, GEN6_ARF_ACC0, 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, GEN6_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, GEN6_ARF_ACC0, 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 GEN6_OPCODE_MAC:
284
         lower_opcode_mac(tc, inst);
285
         break;
286
      case GEN6_OPCODE_MAD:
287
         /* TODO operands must be floats */
288
         break;
289
      case GEN6_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 == TOY_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 == GEN6_OPCODE_WHILE)
333
         nest_level++;
334
 
335
      dist--;
336
   }
337
 
338
   if (ilo_dev_gen(tc->dev) >= ILO_GEN(8))
339
      inst->src[1] = tsrc_imm_d(dist * 16);
340
   else if (ilo_dev_gen(tc->dev) >= ILO_GEN(7))
341
      inst->src[1] = tsrc_imm_w(dist * 2);
342
   else
343
      inst->dst = tdst_imm_w(dist * 2);
344
}
345
 
346
static void
347
patch_if_else_jip(struct toy_compiler *tc, struct toy_inst *inst)
348
{
349
   struct toy_inst *inst2;
350
   int nest_level, dist;
351
   int jip, uip;
352
 
353
   nest_level = 0;
354
   dist = 1;
355
   jip = 0;
356
   uip = 0;
357
 
358
   /* search forward */
359
   LIST_FOR_EACH_ENTRY_FROM(inst2, inst->list.next, &tc->instructions, list) {
360
      if (inst2->marker)
361
         continue;
362
 
363
      if (inst2->opcode == GEN6_OPCODE_ENDIF) {
364
         if (nest_level) {
365
            nest_level--;
366
         }
367
         else {
368
            uip = dist * 2;
369
            if (!jip)
370
               jip = uip;
371
            break;
372
         }
373
      }
374
      else if (inst2->opcode == GEN6_OPCODE_ELSE &&
375
               inst->opcode == GEN6_OPCODE_IF) {
376
         if (!nest_level) {
377
            /* the following instruction */
378
            jip = (dist + 1) * 2;
379
 
380
            if (ilo_dev_gen(tc->dev) == ILO_GEN(6)) {
381
               uip = jip;
382
               break;
383
            }
384
         }
385
      }
386
      else if (inst2->opcode == GEN6_OPCODE_IF) {
387
         nest_level++;
388
      }
389
 
390
      dist++;
391
   }
392
 
393
   if (ilo_dev_gen(tc->dev) >= ILO_GEN(8)) {
394
      inst->dst.type = TOY_TYPE_D;
395
      inst->src[0] = tsrc_imm_d(uip * 8);
396
      inst->src[1] = tsrc_imm_d(jip * 8);
397
   } else if (ilo_dev_gen(tc->dev) >= ILO_GEN(7)) {
398
      /* what should the type be? */
399
      inst->dst.type = TOY_TYPE_D;
400
      inst->src[0].type = TOY_TYPE_D;
401
      inst->src[1] = tsrc_imm_d(uip << 16 | jip);
402
   } else {
403
      inst->dst = tdst_imm_w(jip);
404
   }
405
}
406
 
407
static void
408
patch_endif_jip(struct toy_compiler *tc, struct toy_inst *inst)
409
{
410
   struct toy_inst *inst2;
411
   bool found = false;
412
   int dist = 1;
413
 
414
   /* search forward for instructions that may enable channels */
415
   LIST_FOR_EACH_ENTRY_FROM(inst2, inst->list.next, &tc->instructions, list) {
416
      if (inst2->marker)
417
         continue;
418
 
419
      switch (inst2->opcode) {
420
      case GEN6_OPCODE_ENDIF:
421
      case GEN6_OPCODE_ELSE:
422
      case GEN6_OPCODE_WHILE:
423
         found = true;
424
         break;
425
      default:
426
         break;
427
      }
428
 
429
      if (found)
430
         break;
431
 
432
      dist++;
433
   }
434
 
435
   /* should we set dist to (dist - 1) or 1? */
436
   if (!found)
437
      dist = 1;
438
 
439
   if (ilo_dev_gen(tc->dev) >= ILO_GEN(8))
440
      inst->src[1] = tsrc_imm_d(dist * 16);
441
   else if (ilo_dev_gen(tc->dev) >= ILO_GEN(7))
442
      inst->src[1] = tsrc_imm_w(dist * 2);
443
   else
444
      inst->dst = tdst_imm_w(dist * 2);
445
}
446
 
447
static void
448
patch_break_continue_jip(struct toy_compiler *tc, struct toy_inst *inst)
449
{
450
   struct toy_inst *inst2, *inst3;
451
   int nest_level, dist, jip, uip;
452
 
453
   nest_level = 0;
454
   dist = 1;
455
   jip = 1 * 2;
456
   uip = 1 * 2;
457
 
458
   /* search forward */
459
   LIST_FOR_EACH_ENTRY_FROM(inst2, inst->list.next, &tc->instructions, list) {
460
      if (inst2->marker) {
461
         if (inst2->opcode == TOY_OPCODE_DO)
462
            nest_level++;
463
         continue;
464
      }
465
 
466
      if (inst2->opcode == GEN6_OPCODE_ELSE ||
467
          inst2->opcode == GEN6_OPCODE_ENDIF ||
468
          inst2->opcode == GEN6_OPCODE_WHILE) {
469
         jip = dist * 2;
470
         break;
471
      }
472
 
473
      dist++;
474
   }
475
 
476
   /* go on to determine uip */
477
   inst3 = inst2;
478
   LIST_FOR_EACH_ENTRY_FROM(inst2, &inst3->list, &tc->instructions, list) {
479
      if (inst2->marker) {
480
         if (inst2->opcode == TOY_OPCODE_DO)
481
            nest_level++;
482
         continue;
483
      }
484
 
485
      if (inst2->opcode == GEN6_OPCODE_WHILE) {
486
         if (nest_level) {
487
            nest_level--;
488
         }
489
         else {
490
            /* the following instruction */
491
            if (ilo_dev_gen(tc->dev) == ILO_GEN(6) &&
492
                inst->opcode == GEN6_OPCODE_BREAK)
493
               dist++;
494
 
495
            uip = dist * 2;
496
            break;
497
         }
498
      }
499
 
500
      dist++;
501
   }
502
 
503
   /* should the type be D or W? */
504
   inst->dst.type = TOY_TYPE_D;
505
   if (ilo_dev_gen(tc->dev) >= ILO_GEN(8)) {
506
      inst->src[0] = tsrc_imm_d(uip * 8);
507
      inst->src[1] = tsrc_imm_d(jip * 8);
508
   } else {
509
      inst->src[0].type = TOY_TYPE_D;
510
      inst->src[1] = tsrc_imm_d(uip << 16 | jip);
511
   }
512
}
513
 
514
/**
515
 * Legalize the instructions for assembling.
516
 */
517
void
518
toy_compiler_legalize_for_asm(struct toy_compiler *tc)
519
{
520
   struct toy_inst *inst;
521
   int pc = 0;
522
 
523
   tc_head(tc);
524
   while ((inst = tc_next(tc)) != NULL) {
525
      int i;
526
 
527
      pc++;
528
 
529
      /*
530
       * From the Sandy Bridge PRM, volume 4 part 2, page 112:
531
       *
532
       *     "Specifically, for instructions with a single source, it only
533
       *      uses the first source operand . In this case, the second
534
       *      source operand  must be set to null and also with the same
535
       *      type as the first source operand .  It is a special case
536
       *      when  is an immediate, as an immediate  uses DW3 of
537
       *      the instruction word, which is normally used by .  In this
538
       *      case,  must be programmed with register file ARF and the
539
       *      same data type as ."
540
       *
541
       * Since we already fill unused operands with null, we only need to take
542
       * care of the type.
543
       */
544
      if (tsrc_is_null(inst->src[1]))
545
         inst->src[1].type = inst->src[0].type;
546
 
547
      switch (inst->opcode) {
548
      case GEN6_OPCODE_MATH:
549
         /* math does not support align16 nor exec_size > 8 */
550
         inst->access_mode = GEN6_ALIGN_1;
551
 
552
         if (inst->exec_size == GEN6_EXECSIZE_16) {
553
            /*
554
             * From the Ivy Bridge PRM, volume 4 part 3, page 192:
555
             *
556
             *     "INT DIV function does not support SIMD16."
557
             */
558
            if (ilo_dev_gen(tc->dev) < ILO_GEN(7) ||
559
                inst->cond_modifier == GEN6_MATH_INT_DIV_QUOTIENT ||
560
                inst->cond_modifier == GEN6_MATH_INT_DIV_REMAINDER) {
561
               struct toy_inst *inst2;
562
 
563
               inst->exec_size = GEN6_EXECSIZE_8;
564
               inst->qtr_ctrl = GEN6_QTRCTRL_1Q;
565
 
566
               inst2 = tc_duplicate_inst(tc, inst);
567
               inst2->qtr_ctrl = GEN6_QTRCTRL_2Q;
568
               inst2->dst = tdst_offset(inst2->dst, 1, 0);
569
               inst2->src[0] = tsrc_offset(inst2->src[0], 1, 0);
570
               if (!tsrc_is_null(inst2->src[1]))
571
                  inst2->src[1] = tsrc_offset(inst2->src[1], 1, 0);
572
 
573
               pc++;
574
            }
575
         }
576
         break;
577
      case GEN6_OPCODE_IF:
578
         if (ilo_dev_gen(tc->dev) >= ILO_GEN(7) &&
579
             inst->cond_modifier != GEN6_COND_NONE) {
580
            struct toy_inst *inst2;
581
 
582
            inst2 = tc_duplicate_inst(tc, inst);
583
 
584
            /* replace the original IF by CMP */
585
            inst->opcode = GEN6_OPCODE_CMP;
586
 
587
            /* predicate control instead of condition modifier */
588
            inst2->dst = tdst_null();
589
            inst2->src[0] = tsrc_null();
590
            inst2->src[1] = tsrc_null();
591
            inst2->cond_modifier = GEN6_COND_NONE;
592
            inst2->pred_ctrl = GEN6_PREDCTRL_NORMAL;
593
 
594
            pc++;
595
         }
596
         break;
597
      default:
598
         break;
599
      }
600
 
601
      /* MRF to GRF */
602
      if (ilo_dev_gen(tc->dev) >= ILO_GEN(7)) {
603
         for (i = 0; i < Elements(inst->src); i++) {
604
            if (inst->src[i].file != TOY_FILE_MRF)
605
               continue;
606
            else if (tsrc_is_null(inst->src[i]))
607
               break;
608
 
609
            inst->src[i].file = TOY_FILE_GRF;
610
         }
611
 
612
         if (inst->dst.file == TOY_FILE_MRF)
613
            inst->dst.file = TOY_FILE_GRF;
614
      }
615
   }
616
 
617
   tc->num_instructions = pc;
618
 
619
   /* set JIP/UIP */
620
   tc_head(tc);
621
   while ((inst = tc_next(tc)) != NULL) {
622
      switch (inst->opcode) {
623
      case GEN6_OPCODE_IF:
624
      case GEN6_OPCODE_ELSE:
625
         patch_if_else_jip(tc, inst);
626
         break;
627
      case GEN6_OPCODE_ENDIF:
628
         patch_endif_jip(tc, inst);
629
         break;
630
      case GEN6_OPCODE_WHILE:
631
         patch_while_jip(tc, inst);
632
         break;
633
      case GEN6_OPCODE_BREAK:
634
      case GEN6_OPCODE_CONT:
635
         patch_break_continue_jip(tc, inst);
636
         break;
637
      default:
638
         break;
639
      }
640
   }
641
}