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

« back to all changes in this revision

Viewing changes to src/gallium/drivers/r300/compiler/radeon_compiler_util.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 Tom Stellard <tstellar@gmail.com>
 
3
 *
 
4
 * All Rights Reserved.
 
5
 *
 
6
 * Permission is hereby granted, free of charge, to any person obtaining
 
7
 * a copy of this software and associated documentation files (the
 
8
 * "Software"), to deal in the Software without restriction, including
 
9
 * without limitation the rights to use, copy, modify, merge, publish,
 
10
 * distribute, sublicense, and/or sell copies of the Software, and to
 
11
 * permit persons to whom the Software is furnished to do so, subject to
 
12
 * the following conditions:
 
13
 *
 
14
 * The above copyright notice and this permission notice (including the
 
15
 * next paragraph) shall be included in all copies or substantial
 
16
 * portions of the Software.
 
17
 *
 
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
19
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
20
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 
21
 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
 
22
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
23
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
24
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
25
 *
 
26
 */
 
27
 
 
28
/**
 
29
 * \file
 
30
 */
 
31
 
 
32
#include "radeon_compiler_util.h"
 
33
 
 
34
#include "radeon_compiler.h"
 
35
#include "radeon_dataflow.h"
 
36
/**
 
37
 */
 
38
unsigned int rc_swizzle_to_writemask(unsigned int swz)
 
39
{
 
40
        unsigned int mask = 0;
 
41
        unsigned int i;
 
42
 
 
43
        for(i = 0; i < 4; i++) {
 
44
                mask |= 1 << GET_SWZ(swz, i);
 
45
        }
 
46
        mask &= RC_MASK_XYZW;
 
47
 
 
48
        return mask;
 
49
}
 
50
 
 
51
rc_swizzle get_swz(unsigned int swz, rc_swizzle idx)
 
52
{
 
53
        if (idx & 0x4)
 
54
                return idx;
 
55
        return GET_SWZ(swz, idx);
 
56
}
 
57
 
 
58
/**
 
59
 * The purpose of this function is to standardize the number channels used by
 
60
 * swizzles.  All swizzles regardless of what instruction they are a part of
 
61
 * should have 4 channels initialized with values.
 
62
 * @param channels The number of channels in initial_value that have a
 
63
 * meaningful value.
 
64
 * @return An initialized swizzle that has all of the unused channels set to
 
65
 * RC_SWIZZLE_UNUSED.
 
66
 */
 
67
unsigned int rc_init_swizzle(unsigned int initial_value, unsigned int channels)
 
68
{
 
69
        unsigned int i;
 
70
        for (i = channels; i < 4; i++) {
 
71
                SET_SWZ(initial_value, i, RC_SWIZZLE_UNUSED);
 
72
        }
 
73
        return initial_value;
 
74
}
 
75
 
 
76
unsigned int combine_swizzles4(unsigned int src,
 
77
                rc_swizzle swz_x, rc_swizzle swz_y, rc_swizzle swz_z, rc_swizzle swz_w)
 
78
{
 
79
        unsigned int ret = 0;
 
80
 
 
81
        ret |= get_swz(src, swz_x);
 
82
        ret |= get_swz(src, swz_y) << 3;
 
83
        ret |= get_swz(src, swz_z) << 6;
 
84
        ret |= get_swz(src, swz_w) << 9;
 
85
 
 
86
        return ret;
 
87
}
 
88
 
 
89
unsigned int combine_swizzles(unsigned int src, unsigned int swz)
 
90
{
 
91
        unsigned int ret = 0;
 
92
 
 
93
        ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_X));
 
94
        ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_Y)) << 3;
 
95
        ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_Z)) << 6;
 
96
        ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_W)) << 9;
 
97
 
 
98
        return ret;
 
99
}
 
100
 
 
101
/**
 
102
 * @param mask Must be either RC_MASK_X, RC_MASK_Y, RC_MASK_Z, or RC_MASK_W
 
103
 */
 
104
rc_swizzle rc_mask_to_swizzle(unsigned int mask)
 
105
{
 
106
        switch (mask) {
 
107
        case RC_MASK_X: return RC_SWIZZLE_X;
 
108
        case RC_MASK_Y: return RC_SWIZZLE_Y;
 
109
        case RC_MASK_Z: return RC_SWIZZLE_Z;
 
110
        case RC_MASK_W: return RC_SWIZZLE_W;
 
111
        }
 
112
        return RC_SWIZZLE_UNUSED;
 
113
}
 
114
 
 
115
/* Reorder mask bits according to swizzle. */
 
116
unsigned swizzle_mask(unsigned swizzle, unsigned mask)
 
117
{
 
118
        unsigned ret = 0;
 
119
        for (unsigned chan = 0; chan < 4; ++chan) {
 
120
                unsigned swz = GET_SWZ(swizzle, chan);
 
121
                if (swz < 4)
 
122
                        ret |= GET_BIT(mask, swz) << chan;
 
123
        }
 
124
        return ret;
 
125
}
 
126
 
 
127
static unsigned int srcs_need_rewrite(const struct rc_opcode_info * info)
 
128
{
 
129
        if (info->HasTexture) {
 
130
                return 0;
 
131
        }
 
132
        switch (info->Opcode) {
 
133
                case RC_OPCODE_DP2:
 
134
                case RC_OPCODE_DP3:
 
135
                case RC_OPCODE_DP4:
 
136
                case RC_OPCODE_DDX:
 
137
                case RC_OPCODE_DDY:
 
138
                        return 0;
 
139
                default:
 
140
                        return 1;
 
141
        }
 
142
}
 
143
 
 
144
/**
 
145
 * @return A swizzle the results from converting old_swizzle using
 
146
 * conversion_swizzle
 
147
 */
 
148
unsigned int rc_adjust_channels(
 
149
        unsigned int old_swizzle,
 
150
        unsigned int conversion_swizzle)
 
151
{
 
152
        unsigned int i;
 
153
        unsigned int new_swizzle = rc_init_swizzle(RC_SWIZZLE_UNUSED, 0);
 
154
        for (i = 0; i < 4; i++) {
 
155
                unsigned int new_chan = get_swz(conversion_swizzle, i);
 
156
                if (new_chan == RC_SWIZZLE_UNUSED) {
 
157
                        continue;
 
158
                }
 
159
                SET_SWZ(new_swizzle, new_chan, GET_SWZ(old_swizzle, i));
 
160
        }
 
161
        return new_swizzle;
 
162
}
 
163
 
 
164
static unsigned int rewrite_writemask(
 
165
        unsigned int old_mask,
 
166
        unsigned int conversion_swizzle)
 
167
{
 
168
        unsigned int new_mask = 0;
 
169
        unsigned int i;
 
170
 
 
171
        for (i = 0; i < 4; i++) {
 
172
                if (!GET_BIT(old_mask, i)
 
173
                   || GET_SWZ(conversion_swizzle, i) == RC_SWIZZLE_UNUSED) {
 
174
                        continue;
 
175
                }
 
176
                new_mask |= (1 << GET_SWZ(conversion_swizzle, i));
 
177
        }
 
178
 
 
179
        return new_mask;
 
180
}
 
181
 
 
182
/**
 
183
 * This function rewrites the writemask of sub and adjusts the swizzles
 
184
 * of all its source registers based on the conversion_swizzle.
 
185
 * conversion_swizzle represents a mapping of the old writemask to the
 
186
 * new writemask.  For a detailed description of how conversion swizzles
 
187
 * work see rc_rewrite_swizzle().
 
188
 */
 
189
void rc_pair_rewrite_writemask(
 
190
        struct rc_pair_sub_instruction * sub,
 
191
        unsigned int conversion_swizzle)
 
192
{
 
193
        const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode);
 
194
        unsigned int i;
 
195
 
 
196
        sub->WriteMask = rewrite_writemask(sub->WriteMask, conversion_swizzle);
 
197
 
 
198
        if (!srcs_need_rewrite(info)) {
 
199
                return ;
 
200
        }
 
201
 
 
202
        for (i = 0; i < info->NumSrcRegs; i++) {
 
203
                sub->Arg[i].Swizzle =
 
204
                        rc_adjust_channels(sub->Arg[i].Swizzle,
 
205
                                                conversion_swizzle);
 
206
        }
 
207
}
 
208
 
 
209
static void normal_rewrite_writemask_cb(
 
210
        void * userdata,
 
211
        struct rc_instruction * inst,
 
212
        struct rc_src_register * src)
 
213
{
 
214
        unsigned int * conversion_swizzle = (unsigned int *)userdata;
 
215
        src->Swizzle = rc_adjust_channels(src->Swizzle, *conversion_swizzle);
 
216
}
 
217
 
 
218
/**
 
219
 * This function is the same as rc_pair_rewrite_writemask() except it
 
220
 * operates on normal instructions.
 
221
 */
 
222
void rc_normal_rewrite_writemask(
 
223
        struct rc_instruction * inst,
 
224
        unsigned int conversion_swizzle)
 
225
{
 
226
        struct rc_sub_instruction * sub = &inst->U.I;
 
227
        const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode);
 
228
        sub->DstReg.WriteMask =
 
229
                rewrite_writemask(sub->DstReg.WriteMask, conversion_swizzle);
 
230
 
 
231
        if (info->HasTexture) {
 
232
                unsigned int i;
 
233
                assert(sub->TexSwizzle == RC_SWIZZLE_XYZW);
 
234
                for (i = 0; i < 4; i++) {
 
235
                        unsigned int swz = GET_SWZ(conversion_swizzle, i);
 
236
                        if (swz > 3)
 
237
                                continue;
 
238
                        SET_SWZ(sub->TexSwizzle, swz, i);
 
239
                }
 
240
        }
 
241
 
 
242
        if (!srcs_need_rewrite(info)) {
 
243
                return;
 
244
        }
 
245
 
 
246
        rc_for_all_reads_src(inst, normal_rewrite_writemask_cb,
 
247
                                                        &conversion_swizzle);
 
248
}
 
249
 
 
250
/**
 
251
 * This function replaces each value 'swz' in swizzle with the value of
 
252
 * GET_SWZ(conversion_swizzle, swz).  So, if you want to change all the X's
 
253
 * in swizzle to Y, then conversion_swizzle should be Y___ (0xff9).  If you want
 
254
 * to change all the Y's in swizzle to X, then conversion_swizzle should be
 
255
 * _X__ (0xfc7).  If you want to change the Y's to X and the X's to Y, then
 
256
 * conversion swizzle should be YX__ (0xfc1).
 
257
 * @param swizzle The swizzle to change
 
258
 * @param conversion_swizzle Describes the conversion to perform on the swizzle
 
259
 * @return A converted swizzle
 
260
 */
 
261
unsigned int rc_rewrite_swizzle(
 
262
        unsigned int swizzle,
 
263
        unsigned int conversion_swizzle)
 
264
{
 
265
        unsigned int chan;
 
266
        unsigned int out_swizzle = swizzle;
 
267
 
 
268
        for (chan = 0; chan < 4; chan++) {
 
269
                unsigned int swz = GET_SWZ(swizzle, chan);
 
270
                unsigned int new_swz;
 
271
                if (swz > 3) {
 
272
                        SET_SWZ(out_swizzle, chan, swz);
 
273
                } else {
 
274
                        new_swz = GET_SWZ(conversion_swizzle, swz);
 
275
                        if (new_swz != RC_SWIZZLE_UNUSED) {
 
276
                                SET_SWZ(out_swizzle, chan, new_swz);
 
277
                        } else {
 
278
                                SET_SWZ(out_swizzle, chan, swz);
 
279
                        }
 
280
                }
 
281
        }
 
282
        return out_swizzle;
 
283
}
 
284
 
 
285
/**
 
286
 * Left multiplication of a register with a swizzle
 
287
 */
 
288
struct rc_src_register lmul_swizzle(unsigned int swizzle, struct rc_src_register srcreg)
 
289
{
 
290
        struct rc_src_register tmp = srcreg;
 
291
        int i;
 
292
        tmp.Swizzle = 0;
 
293
        tmp.Negate = 0;
 
294
        for(i = 0; i < 4; ++i) {
 
295
                rc_swizzle swz = GET_SWZ(swizzle, i);
 
296
                if (swz < 4) {
 
297
                        tmp.Swizzle |= GET_SWZ(srcreg.Swizzle, swz) << (i*3);
 
298
                        tmp.Negate |= GET_BIT(srcreg.Negate, swz) << i;
 
299
                } else {
 
300
                        tmp.Swizzle |= swz << (i*3);
 
301
                }
 
302
        }
 
303
        return tmp;
 
304
}
 
305
 
 
306
void reset_srcreg(struct rc_src_register* reg)
 
307
{
 
308
        memset(reg, 0, sizeof(struct rc_src_register));
 
309
        reg->Swizzle = RC_SWIZZLE_XYZW;
 
310
}
 
311
 
 
312
unsigned int rc_src_reads_dst_mask(
 
313
                rc_register_file src_file,
 
314
                unsigned int src_idx,
 
315
                unsigned int src_swz,
 
316
                rc_register_file dst_file,
 
317
                unsigned int dst_idx,
 
318
                unsigned int dst_mask)
 
319
{
 
320
        if (src_file != dst_file || src_idx != dst_idx) {
 
321
                return RC_MASK_NONE;
 
322
        }
 
323
        return dst_mask & rc_swizzle_to_writemask(src_swz);
 
324
}
 
325
 
 
326
/**
 
327
 * @return A bit mask specifying whether this swizzle will select from an RGB
 
328
 * source, an Alpha source, or both.
 
329
 */
 
330
unsigned int rc_source_type_swz(unsigned int swizzle)
 
331
{
 
332
        unsigned int chan;
 
333
        unsigned int swz = RC_SWIZZLE_UNUSED;
 
334
        unsigned int ret = RC_SOURCE_NONE;
 
335
 
 
336
        for(chan = 0; chan < 4; chan++) {
 
337
                swz = GET_SWZ(swizzle, chan);
 
338
                if (swz == RC_SWIZZLE_W) {
 
339
                        ret |= RC_SOURCE_ALPHA;
 
340
                } else if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y
 
341
                                                || swz == RC_SWIZZLE_Z) {
 
342
                        ret |= RC_SOURCE_RGB;
 
343
                }
 
344
        }
 
345
        return ret;
 
346
}
 
347
 
 
348
unsigned int rc_source_type_mask(unsigned int mask)
 
349
{
 
350
        unsigned int ret = RC_SOURCE_NONE;
 
351
 
 
352
        if (mask & RC_MASK_XYZ)
 
353
                ret |= RC_SOURCE_RGB;
 
354
 
 
355
        if (mask & RC_MASK_W)
 
356
                ret |= RC_SOURCE_ALPHA;
 
357
 
 
358
        return ret;
 
359
}
 
360
 
 
361
struct src_select {
 
362
        rc_register_file File;
 
363
        int Index;
 
364
        unsigned int SrcType;
 
365
};
 
366
 
 
367
struct can_use_presub_data {
 
368
        struct src_select Selects[5];
 
369
        unsigned int SelectCount;
 
370
        const struct rc_src_register * ReplaceReg;
 
371
        unsigned int ReplaceRemoved;
 
372
};
 
373
 
 
374
static void can_use_presub_data_add_select(
 
375
        struct can_use_presub_data * data,
 
376
        rc_register_file file,
 
377
        unsigned int index,
 
378
        unsigned int src_type)
 
379
{
 
380
        struct src_select * select;
 
381
 
 
382
        select = &data->Selects[data->SelectCount++];
 
383
        select->File = file;
 
384
        select->Index = index;
 
385
        select->SrcType = src_type;
 
386
}
 
387
 
 
388
/**
 
389
 * This callback function counts the number of sources in inst that are
 
390
 * different from the sources in can_use_presub_data->RemoveSrcs.
 
391
 */
 
392
static void can_use_presub_read_cb(
 
393
        void * userdata,
 
394
        struct rc_instruction * inst,
 
395
        struct rc_src_register * src)
 
396
{
 
397
        struct can_use_presub_data * d = userdata;
 
398
 
 
399
        if (!d->ReplaceRemoved && src == d->ReplaceReg) {
 
400
                d->ReplaceRemoved = 1;
 
401
                return;
 
402
        }
 
403
 
 
404
        if (src->File == RC_FILE_NONE)
 
405
                return;
 
406
 
 
407
        can_use_presub_data_add_select(d, src->File, src->Index,
 
408
                                        rc_source_type_swz(src->Swizzle));
 
409
}
 
410
 
 
411
unsigned int rc_inst_can_use_presub(
 
412
        struct rc_instruction * inst,
 
413
        rc_presubtract_op presub_op,
 
414
        unsigned int presub_writemask,
 
415
        const struct rc_src_register * replace_reg,
 
416
        const struct rc_src_register * presub_src0,
 
417
        const struct rc_src_register * presub_src1)
 
418
{
 
419
        struct can_use_presub_data d;
 
420
        unsigned int num_presub_srcs;
 
421
        unsigned int i;
 
422
        const struct rc_opcode_info * info =
 
423
                                        rc_get_opcode_info(inst->U.I.Opcode);
 
424
        int rgb_count = 0, alpha_count = 0;
 
425
        unsigned int src_type0, src_type1;
 
426
 
 
427
        if (presub_op == RC_PRESUB_NONE) {
 
428
                return 1;
 
429
        }
 
430
 
 
431
        if (info->HasTexture) {
 
432
                return 0;
 
433
        }
 
434
 
 
435
        /* We can't use more than one presubtract value in an
 
436
         * instruction, unless the two prsubtract operations
 
437
         * are the same and read from the same registers.
 
438
         * XXX For now we will limit instructions to only one presubtract
 
439
         * value.*/
 
440
        if (inst->U.I.PreSub.Opcode != RC_PRESUB_NONE) {
 
441
                return 0;
 
442
        }
 
443
 
 
444
        memset(&d, 0, sizeof(d));
 
445
        d.ReplaceReg = replace_reg;
 
446
 
 
447
        rc_for_all_reads_src(inst, can_use_presub_read_cb, &d);
 
448
 
 
449
        num_presub_srcs = rc_presubtract_src_reg_count(presub_op);
 
450
 
 
451
        src_type0 = rc_source_type_swz(presub_src0->Swizzle);
 
452
        can_use_presub_data_add_select(&d,
 
453
                presub_src0->File,
 
454
                presub_src0->Index,
 
455
                src_type0);
 
456
 
 
457
        if (num_presub_srcs > 1) {
 
458
                src_type1 = rc_source_type_swz(presub_src1->Swizzle);
 
459
                can_use_presub_data_add_select(&d,
 
460
                        presub_src1->File,
 
461
                        presub_src1->Index,
 
462
                        src_type1);
 
463
 
 
464
                /* Even if both of the presub sources read from the same
 
465
                 * register, we still need to use 2 different source selects
 
466
                 * for them, so we need to increment the count to compensate.
 
467
                 */
 
468
                if (presub_src0->File == presub_src1->File
 
469
                    && presub_src0->Index == presub_src1->Index) {
 
470
                        if (src_type0 & src_type1 & RC_SOURCE_RGB) {
 
471
                                rgb_count++;
 
472
                        }
 
473
                        if (src_type0 & src_type1 & RC_SOURCE_ALPHA) {
 
474
                                alpha_count++;
 
475
                        }
 
476
                }
 
477
        }
 
478
 
 
479
        /* Count the number of source selects for Alpha and RGB.  If we
 
480
         * encounter two of the same source selects then we can ignore the
 
481
         * first one. */
 
482
        for (i = 0; i < d.SelectCount; i++) {
 
483
                unsigned int j;
 
484
                unsigned int src_type = d.Selects[i].SrcType;
 
485
                for (j = i + 1; j < d.SelectCount; j++) {
 
486
                        if (d.Selects[i].File == d.Selects[j].File
 
487
                            && d.Selects[i].Index == d.Selects[j].Index) {
 
488
                                src_type &= ~d.Selects[j].SrcType;
 
489
                        }
 
490
                }
 
491
                if (src_type & RC_SOURCE_RGB) {
 
492
                        rgb_count++;
 
493
                }
 
494
 
 
495
                if (src_type & RC_SOURCE_ALPHA) {
 
496
                        alpha_count++;
 
497
                }
 
498
        }
 
499
 
 
500
        if (rgb_count > 3 || alpha_count > 3) {
 
501
                return 0;
 
502
        }
 
503
 
 
504
        return 1;
 
505
}
 
506
 
 
507
struct max_data {
 
508
        unsigned int Max;
 
509
        unsigned int HasFileType;
 
510
        rc_register_file File;
 
511
};
 
512
 
 
513
static void max_callback(
 
514
        void * userdata,
 
515
        struct rc_instruction * inst,
 
516
        rc_register_file file,
 
517
        unsigned int index,
 
518
        unsigned int mask)
 
519
{
 
520
        struct max_data * d = (struct max_data*)userdata;
 
521
        if (file == d->File && (!d->HasFileType || index > d->Max)) {
 
522
                d->Max = index;
 
523
                d->HasFileType = 1;
 
524
        }
 
525
}
 
526
 
 
527
/**
 
528
 * @return The maximum index of the specified register file used by the
 
529
 * program.
 
530
 */
 
531
int rc_get_max_index(
 
532
        struct radeon_compiler * c,
 
533
        rc_register_file file)
 
534
{
 
535
        struct max_data data;
 
536
        struct rc_instruction * inst;
 
537
        data.Max = 0;
 
538
        data.HasFileType = 0;
 
539
        data.File = file;
 
540
        for (inst = c->Program.Instructions.Next;
 
541
                                        inst != &c->Program.Instructions;
 
542
                                        inst = inst->Next) {
 
543
                rc_for_all_reads_mask(inst, max_callback, &data);
 
544
                rc_for_all_writes_mask(inst, max_callback, &data);
 
545
        }
 
546
        if (!data.HasFileType) {
 
547
                return -1;
 
548
        } else {
 
549
                return data.Max;
 
550
        }
 
551
}
 
552
 
 
553
static unsigned int get_source_readmask(
 
554
        struct rc_pair_sub_instruction * sub,
 
555
        unsigned int source,
 
556
        unsigned int src_type)
 
557
{
 
558
        unsigned int i;
 
559
        unsigned int readmask = 0;
 
560
        const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode);
 
561
 
 
562
        for (i = 0; i < info->NumSrcRegs; i++) {
 
563
                if (sub->Arg[i].Source != source
 
564
                    || src_type != rc_source_type_swz(sub->Arg[i].Swizzle)) {
 
565
                        continue;
 
566
                }
 
567
                readmask |= rc_swizzle_to_writemask(sub->Arg[i].Swizzle);
 
568
        }
 
569
        return readmask;
 
570
}
 
571
 
 
572
/**
 
573
 * This function attempts to remove a source from a pair instructions.
 
574
 * @param inst
 
575
 * @param src_type RC_SOURCE_RGB, RC_SOURCE_ALPHA, or both bitwise or'd
 
576
 * @param source The index of the source to remove
 
577
 * @param new_readmask A mask representing the components that are read by
 
578
 * the source that is intended to replace the one you are removing.  If you
 
579
 * want to remove a source only and not replace it, this parameter should be
 
580
 * zero.
 
581
 * @return 1 if the source was successfully removed, 0 if it was not
 
582
 */
 
583
unsigned int rc_pair_remove_src(
 
584
        struct rc_instruction * inst,
 
585
        unsigned int src_type,
 
586
        unsigned int source,
 
587
        unsigned int new_readmask)
 
588
{
 
589
        unsigned int readmask = 0;
 
590
 
 
591
        readmask |= get_source_readmask(&inst->U.P.RGB, source, src_type);
 
592
        readmask |= get_source_readmask(&inst->U.P.Alpha, source, src_type);
 
593
 
 
594
        if ((new_readmask & readmask) != readmask)
 
595
                return 0;
 
596
 
 
597
        if (src_type & RC_SOURCE_RGB) {
 
598
                memset(&inst->U.P.RGB.Src[source], 0,
 
599
                        sizeof(struct rc_pair_instruction_source));
 
600
        }
 
601
 
 
602
        if (src_type & RC_SOURCE_ALPHA) {
 
603
                memset(&inst->U.P.Alpha.Src[source], 0,
 
604
                        sizeof(struct rc_pair_instruction_source));
 
605
        }
 
606
 
 
607
        return 1;
 
608
}
 
609
 
 
610
/**
 
611
 * @return RC_OPCODE_NOOP if inst is not a flow control instruction.
 
612
 * @return The opcode of inst if it is a flow control instruction.
 
613
 */
 
614
rc_opcode rc_get_flow_control_inst(struct rc_instruction * inst)
 
615
{
 
616
        const struct rc_opcode_info * info;
 
617
        if (inst->Type == RC_INSTRUCTION_NORMAL) {
 
618
                info = rc_get_opcode_info(inst->U.I.Opcode);
 
619
        } else {
 
620
                info = rc_get_opcode_info(inst->U.P.RGB.Opcode);
 
621
                /*A flow control instruction shouldn't have an alpha
 
622
                 * instruction.*/
 
623
                assert(!info->IsFlowControl ||
 
624
                                inst->U.P.Alpha.Opcode == RC_OPCODE_NOP);
 
625
        }
 
626
 
 
627
        if (info->IsFlowControl)
 
628
                return info->Opcode;
 
629
        else
 
630
                return RC_OPCODE_NOP;
 
631
 
 
632
}
 
633
 
 
634
/**
 
635
 * @return The BGNLOOP instruction that starts the loop ended by endloop.
 
636
 */
 
637
struct rc_instruction * rc_match_endloop(struct rc_instruction * endloop)
 
638
{
 
639
        unsigned int endloop_count = 0;
 
640
        struct rc_instruction * inst;
 
641
        for (inst = endloop->Prev; inst != endloop; inst = inst->Prev) {
 
642
                rc_opcode op = rc_get_flow_control_inst(inst);
 
643
                if (op == RC_OPCODE_ENDLOOP) {
 
644
                        endloop_count++;
 
645
                } else if (op == RC_OPCODE_BGNLOOP) {
 
646
                        if (endloop_count == 0) {
 
647
                                return inst;
 
648
                        } else {
 
649
                                endloop_count--;
 
650
                        }
 
651
                }
 
652
        }
 
653
        return NULL;
 
654
}
 
655
 
 
656
/**
 
657
 * @return The ENDLOOP instruction that ends the loop started by bgnloop.
 
658
 */
 
659
struct rc_instruction * rc_match_bgnloop(struct rc_instruction * bgnloop)
 
660
{
 
661
        unsigned int bgnloop_count = 0;
 
662
        struct rc_instruction * inst;
 
663
        for (inst = bgnloop->Next; inst!=bgnloop; inst = inst->Next) {
 
664
                rc_opcode op = rc_get_flow_control_inst(inst);
 
665
                if (op == RC_OPCODE_BGNLOOP) {
 
666
                        bgnloop_count++;
 
667
                } else if (op == RC_OPCODE_ENDLOOP) {
 
668
                        if (bgnloop_count == 0) {
 
669
                                return inst;
 
670
                        } else {
 
671
                                bgnloop_count--;
 
672
                        }
 
673
                }
 
674
        }
 
675
        return NULL;
 
676
}
 
677
 
 
678
/**
 
679
 * @return A conversion swizzle for converting from old_mask->new_mask
 
680
 */
 
681
unsigned int rc_make_conversion_swizzle(
 
682
        unsigned int old_mask,
 
683
        unsigned int new_mask)
 
684
{
 
685
        unsigned int conversion_swizzle = rc_init_swizzle(RC_SWIZZLE_UNUSED, 0);
 
686
        unsigned int old_idx;
 
687
        unsigned int new_idx = 0;
 
688
        for (old_idx = 0; old_idx < 4; old_idx++) {
 
689
                if (!GET_BIT(old_mask, old_idx))
 
690
                        continue;
 
691
                for ( ; new_idx < 4; new_idx++) {
 
692
                        if (GET_BIT(new_mask, new_idx)) {
 
693
                                SET_SWZ(conversion_swizzle, old_idx, new_idx);
 
694
                                new_idx++;
 
695
                                break;
 
696
                        }
 
697
                }
 
698
        }
 
699
        return conversion_swizzle;
 
700
}
 
701
 
 
702
/**
 
703
 * @return 1 if the register contains an immediate value, 0 otherwise.
 
704
 */
 
705
unsigned int rc_src_reg_is_immediate(
 
706
        struct radeon_compiler * c,
 
707
        unsigned int file,
 
708
        unsigned int index)
 
709
{
 
710
        return file == RC_FILE_CONSTANT &&
 
711
        c->Program.Constants.Constants[index].Type == RC_CONSTANT_IMMEDIATE;
 
712
}
 
713
 
 
714
/**
 
715
 * @return The immediate value in the specified register.
 
716
 */
 
717
float rc_get_constant_value(
 
718
        struct radeon_compiler * c,
 
719
        unsigned int index,
 
720
        unsigned int swizzle,
 
721
        unsigned int negate,
 
722
        unsigned int chan)
 
723
{
 
724
        float base = 1.0f;
 
725
        int swz = GET_SWZ(swizzle, chan);
 
726
        if(swz >= 4 || index >= c->Program.Constants.Count ){
 
727
                rc_error(c, "get_constant_value: Can't find a value.\n");
 
728
                return 0.0f;
 
729
        }
 
730
        if(GET_BIT(negate, chan)){
 
731
                base = -1.0f;
 
732
        }
 
733
        return base *
 
734
                c->Program.Constants.Constants[index].u.Immediate[swz];
 
735
}
 
736
 
 
737
/**
 
738
 * This function returns the component value (RC_SWIZZLE_*) of the first used
 
739
 * channel in the swizzle.  This is only useful for scalar instructions that are
 
740
 * known to use only one channel of the swizzle.
 
741
 */
 
742
unsigned int rc_get_scalar_src_swz(unsigned int swizzle)
 
743
{
 
744
        unsigned int swz, chan;
 
745
        for (chan = 0; chan < 4; chan++) {
 
746
                swz = GET_SWZ(swizzle, chan);
 
747
                if (swz != RC_SWIZZLE_UNUSED) {
 
748
                        break;
 
749
                }
 
750
        }
 
751
        assert(swz != RC_SWIZZLE_UNUSED);
 
752
        return swz;
 
753
}