Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / auxiliary / gallivm / lp_bld_swizzle.c
1 /**************************************************************************
2  *
3  * Copyright 2009 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * 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, sub license, 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 portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27
28 /**
29  * @file
30  * Helper functions for swizzling/shuffling.
31  *
32  * @author Jose Fonseca <jfonseca@vmware.com>
33  */
34
35
36 #include "util/u_debug.h"
37
38 #include "lp_bld_type.h"
39 #include "lp_bld_const.h"
40 #include "lp_bld_init.h"
41 #include "lp_bld_logic.h"
42 #include "lp_bld_swizzle.h"
43
44
45 LLVMValueRef
46 lp_build_broadcast(struct gallivm_state *gallivm,
47                    LLVMTypeRef vec_type,
48                    LLVMValueRef scalar)
49 {
50    const unsigned n = LLVMGetVectorSize(vec_type);
51    LLVMValueRef res;
52    unsigned i;
53
54    res = LLVMGetUndef(vec_type);
55    for(i = 0; i < n; ++i) {
56       LLVMValueRef index = lp_build_const_int32(gallivm, i);
57       res = LLVMBuildInsertElement(gallivm->builder, res, scalar, index, "");
58    }
59
60    return res;
61 }
62
63
64 /**
65  * Broadcast
66  */
67 LLVMValueRef
68 lp_build_broadcast_scalar(struct lp_build_context *bld,
69                           LLVMValueRef scalar)
70 {
71    LLVMBuilderRef builder = bld->gallivm->builder;
72    const struct lp_type type = bld->type;
73
74    assert(lp_check_elem_type(type, LLVMTypeOf(scalar)));
75
76    if (type.length == 1) {
77       return scalar;
78    }
79    else {
80       LLVMValueRef res;
81
82 #if HAVE_LLVM >= 0x207
83       /* The shuffle vector is always made of int32 elements */
84       struct lp_type i32_vec_type = lp_type_int_vec(32);
85       i32_vec_type.length = type.length;
86
87       res = LLVMBuildInsertElement(builder, bld->undef, scalar,
88                                    lp_build_const_int32(bld->gallivm, 0), "");
89       res = LLVMBuildShuffleVector(builder, res, bld->undef,
90                                    lp_build_const_int_vec(bld->gallivm, i32_vec_type, 0), "");
91 #else
92       /* XXX: The above path provokes a bug in LLVM 2.6 */
93       unsigned i;
94       res = bld->undef;
95       for(i = 0; i < type.length; ++i) {
96          LLVMValueRef index = lp_build_const_int32(bld->gallivm, i);
97          res = LLVMBuildInsertElement(builder, res, scalar, index, "");
98       }
99 #endif
100       return res;
101    }
102 }
103
104
105 /**
106  * Combined extract and broadcast (or a mere shuffle when the two types match)
107  */
108 LLVMValueRef
109 lp_build_extract_broadcast(struct gallivm_state *gallivm,
110                            struct lp_type src_type,
111                            struct lp_type dst_type,
112                            LLVMValueRef vector,
113                            LLVMValueRef index)
114 {
115    LLVMTypeRef i32t = LLVMInt32TypeInContext(gallivm->context);
116    LLVMValueRef res;
117
118    assert(src_type.floating == dst_type.floating);
119    assert(src_type.width    == dst_type.width);
120
121    assert(lp_check_value(src_type, vector));
122    assert(LLVMTypeOf(index) == i32t);
123
124    if (src_type.length == 1) {
125       if (dst_type.length == 1) {
126          /*
127           * Trivial scalar -> scalar.
128           */
129
130          res = vector;
131       }
132       else {
133          /*
134           * Broadcast scalar -> vector.
135           */
136
137          res = lp_build_broadcast(gallivm,
138                                   lp_build_vec_type(gallivm, dst_type),
139                                   vector);
140       }
141    }
142    else {
143       if (dst_type.length == src_type.length) {
144          /*
145           * Special shuffle of the same size.
146           */
147
148          LLVMValueRef shuffle;
149          shuffle = lp_build_broadcast(gallivm,
150                                       LLVMVectorType(i32t, dst_type.length),
151                                       index);
152          res = LLVMBuildShuffleVector(gallivm->builder, vector,
153                                       LLVMGetUndef(lp_build_vec_type(gallivm, dst_type)),
154                                       shuffle, "");
155       }
156       else {
157          LLVMValueRef scalar;
158          scalar = LLVMBuildExtractElement(gallivm->builder, vector, index, "");
159          if (dst_type.length == 1) {
160             /*
161              * Trivial extract scalar from vector.
162              */
163
164             res = scalar;
165          }
166          else {
167             /*
168              * General case of different sized vectors.
169              */
170
171             res = lp_build_broadcast(gallivm,
172                                      lp_build_vec_type(gallivm, dst_type),
173                                      vector);
174          }
175       }
176    }
177
178    return res;
179 }
180
181
182 /**
183  * Swizzle one channel into all other three channels.
184  */
185 LLVMValueRef
186 lp_build_swizzle_scalar_aos(struct lp_build_context *bld,
187                             LLVMValueRef a,
188                             unsigned channel)
189 {
190    LLVMBuilderRef builder = bld->gallivm->builder;
191    const struct lp_type type = bld->type;
192    const unsigned n = type.length;
193    unsigned i, j;
194
195    if(a == bld->undef || a == bld->zero || a == bld->one)
196       return a;
197
198    /* XXX: SSE3 has PSHUFB which should be better than bitmasks, but forcing
199     * using shuffles here actually causes worst results. More investigation is
200     * needed. */
201    if (type.width >= 16) {
202       /*
203        * Shuffle.
204        */
205       LLVMTypeRef elem_type = LLVMInt32TypeInContext(bld->gallivm->context);
206       LLVMValueRef shuffles[LP_MAX_VECTOR_LENGTH];
207
208       for(j = 0; j < n; j += 4)
209          for(i = 0; i < 4; ++i)
210             shuffles[j + i] = LLVMConstInt(elem_type, j + channel, 0);
211
212       return LLVMBuildShuffleVector(builder, a, bld->undef, LLVMConstVector(shuffles, n), "");
213    }
214    else {
215       /*
216        * Bit mask and recursive shifts
217        *
218        *   XYZW XYZW .... XYZW  <= input
219        *   0Y00 0Y00 .... 0Y00
220        *   YY00 YY00 .... YY00
221        *   YYYY YYYY .... YYYY  <= output
222        */
223       struct lp_type type4;
224       const char shifts[4][2] = {
225          { 1,  2},
226          {-1,  2},
227          { 1, -2},
228          {-1, -2}
229       };
230       unsigned i;
231
232       a = LLVMBuildAnd(builder, a,
233                        lp_build_const_mask_aos(bld->gallivm,
234                                                type, 1 << channel), "");
235
236       /*
237        * Build a type where each element is an integer that cover the four
238        * channels.
239        */
240
241       type4 = type;
242       type4.floating = FALSE;
243       type4.width *= 4;
244       type4.length /= 4;
245
246       a = LLVMBuildBitCast(builder, a, lp_build_vec_type(bld->gallivm, type4), "");
247
248       for(i = 0; i < 2; ++i) {
249          LLVMValueRef tmp = NULL;
250          int shift = shifts[channel][i];
251
252 #ifdef PIPE_ARCH_LITTLE_ENDIAN
253          shift = -shift;
254 #endif
255
256          if(shift > 0)
257             tmp = LLVMBuildLShr(builder, a, lp_build_const_int_vec(bld->gallivm, type4, shift*type.width), "");
258          if(shift < 0)
259             tmp = LLVMBuildShl(builder, a, lp_build_const_int_vec(bld->gallivm, type4, -shift*type.width), "");
260
261          assert(tmp);
262          if(tmp)
263             a = LLVMBuildOr(builder, a, tmp, "");
264       }
265
266       return LLVMBuildBitCast(builder, a, lp_build_vec_type(bld->gallivm, type), "");
267    }
268 }
269
270
271 LLVMValueRef
272 lp_build_swizzle_aos(struct lp_build_context *bld,
273                      LLVMValueRef a,
274                      const unsigned char swizzles[4])
275 {
276    LLVMBuilderRef builder = bld->gallivm->builder;
277    const struct lp_type type = bld->type;
278    const unsigned n = type.length;
279    unsigned i, j;
280
281    if (swizzles[0] == PIPE_SWIZZLE_RED &&
282        swizzles[1] == PIPE_SWIZZLE_GREEN &&
283        swizzles[2] == PIPE_SWIZZLE_BLUE &&
284        swizzles[3] == PIPE_SWIZZLE_ALPHA) {
285       return a;
286    }
287
288    if (swizzles[0] == swizzles[1] &&
289        swizzles[1] == swizzles[2] &&
290        swizzles[2] == swizzles[3]) {
291       switch (swizzles[0]) {
292       case PIPE_SWIZZLE_RED:
293       case PIPE_SWIZZLE_GREEN:
294       case PIPE_SWIZZLE_BLUE:
295       case PIPE_SWIZZLE_ALPHA:
296          return lp_build_swizzle_scalar_aos(bld, a, swizzles[0]);
297       case PIPE_SWIZZLE_ZERO:
298          return bld->zero;
299       case PIPE_SWIZZLE_ONE:
300          return bld->one;
301       default:
302          assert(0);
303          return bld->undef;
304       }
305    }
306
307    if (type.width >= 16) {
308       /*
309        * Shuffle.
310        */
311       LLVMValueRef undef = LLVMGetUndef(lp_build_elem_type(bld->gallivm, type));
312       LLVMTypeRef i32t = LLVMInt32TypeInContext(bld->gallivm->context);
313       LLVMValueRef shuffles[LP_MAX_VECTOR_LENGTH];
314       LLVMValueRef aux[LP_MAX_VECTOR_LENGTH];
315
316       memset(aux, 0, sizeof aux);
317
318       for(j = 0; j < n; j += 4) {
319          for(i = 0; i < 4; ++i) {
320             unsigned shuffle;
321             switch (swizzles[i]) {
322             default:
323                assert(0);
324                /* fall through */
325             case PIPE_SWIZZLE_RED:
326             case PIPE_SWIZZLE_GREEN:
327             case PIPE_SWIZZLE_BLUE:
328             case PIPE_SWIZZLE_ALPHA:
329                shuffle = j + swizzles[i];
330                break;
331             case PIPE_SWIZZLE_ZERO:
332                shuffle = type.length + 0;
333                if (!aux[0]) {
334                   aux[0] = lp_build_const_elem(bld->gallivm, type, 0.0);
335                }
336                break;
337             case PIPE_SWIZZLE_ONE:
338                shuffle = type.length + 1;
339                if (!aux[1]) {
340                   aux[1] = lp_build_const_elem(bld->gallivm, type, 1.0);
341                }
342                break;
343             }
344             shuffles[j + i] = LLVMConstInt(i32t, shuffle, 0);
345          }
346       }
347
348       for (i = 0; i < n; ++i) {
349          if (!aux[i]) {
350             aux[i] = undef;
351          }
352       }
353
354       return LLVMBuildShuffleVector(builder, a,
355                                     LLVMConstVector(aux, n),
356                                     LLVMConstVector(shuffles, n), "");
357    } else {
358       /*
359        * Bit mask and shifts.
360        *
361        * For example, this will convert BGRA to RGBA by doing
362        *
363        *   rgba = (bgra & 0x00ff0000) >> 16
364        *        | (bgra & 0xff00ff00)
365        *        | (bgra & 0x000000ff) << 16
366        *
367        * This is necessary not only for faster cause, but because X86 backend
368        * will refuse shuffles of <4 x i8> vectors
369        */
370       LLVMValueRef res;
371       struct lp_type type4;
372       unsigned cond = 0;
373       unsigned chan;
374       int shift;
375
376       /*
377        * Start with a mixture of 1 and 0.
378        */
379       for (chan = 0; chan < 4; ++chan) {
380          if (swizzles[chan] == PIPE_SWIZZLE_ONE) {
381             cond |= 1 << chan;
382          }
383       }
384       res = lp_build_select_aos(bld, cond, bld->one, bld->zero);
385
386       /*
387        * Build a type where each element is an integer that cover the four
388        * channels.
389        */
390       type4 = type;
391       type4.floating = FALSE;
392       type4.width *= 4;
393       type4.length /= 4;
394
395       a = LLVMBuildBitCast(builder, a, lp_build_vec_type(bld->gallivm, type4), "");
396       res = LLVMBuildBitCast(builder, res, lp_build_vec_type(bld->gallivm, type4), "");
397
398       /*
399        * Mask and shift the channels, trying to group as many channels in the
400        * same shift as possible
401        */
402       for (shift = -3; shift <= 3; ++shift) {
403          unsigned long long mask = 0;
404
405          assert(type4.width <= sizeof(mask)*8);
406
407          for (chan = 0; chan < 4; ++chan) {
408             /* FIXME: big endian */
409             if (swizzles[chan] < 4 &&
410                 chan - swizzles[chan] == shift) {
411                mask |= ((1ULL << type.width) - 1) << (swizzles[chan] * type.width);
412             }
413          }
414
415          if (mask) {
416             LLVMValueRef masked;
417             LLVMValueRef shifted;
418
419             if (0)
420                debug_printf("shift = %i, mask = 0x%08llx\n", shift, mask);
421
422             masked = LLVMBuildAnd(builder, a,
423                                   lp_build_const_int_vec(bld->gallivm, type4, mask), "");
424             if (shift > 0) {
425                shifted = LLVMBuildShl(builder, masked,
426                                       lp_build_const_int_vec(bld->gallivm, type4, shift*type.width), "");
427             } else if (shift < 0) {
428                shifted = LLVMBuildLShr(builder, masked,
429                                        lp_build_const_int_vec(bld->gallivm, type4, -shift*type.width), "");
430             } else {
431                shifted = masked;
432             }
433
434             res = LLVMBuildOr(builder, res, shifted, "");
435          }
436       }
437
438       return LLVMBuildBitCast(builder, res,
439                               lp_build_vec_type(bld->gallivm, type), "");
440    }
441 }
442
443
444 /**
445  * Extended swizzle of a single channel of a SoA vector.
446  *
447  * @param bld         building context
448  * @param unswizzled  array with the 4 unswizzled values
449  * @param swizzle     one of the PIPE_SWIZZLE_*
450  *
451  * @return  the swizzled value.
452  */
453 LLVMValueRef
454 lp_build_swizzle_soa_channel(struct lp_build_context *bld,
455                              const LLVMValueRef *unswizzled,
456                              unsigned swizzle)
457 {
458    switch (swizzle) {
459    case PIPE_SWIZZLE_RED:
460    case PIPE_SWIZZLE_GREEN:
461    case PIPE_SWIZZLE_BLUE:
462    case PIPE_SWIZZLE_ALPHA:
463       return unswizzled[swizzle];
464    case PIPE_SWIZZLE_ZERO:
465       return bld->zero;
466    case PIPE_SWIZZLE_ONE:
467       return bld->one;
468    default:
469       assert(0);
470       return bld->undef;
471    }
472 }
473
474
475 /**
476  * Extended swizzle of a SoA vector.
477  *
478  * @param bld         building context
479  * @param unswizzled  array with the 4 unswizzled values
480  * @param swizzles    array of PIPE_SWIZZLE_*
481  * @param swizzled    output swizzled values
482  */
483 void
484 lp_build_swizzle_soa(struct lp_build_context *bld,
485                      const LLVMValueRef *unswizzled,
486                      const unsigned char swizzles[4],
487                      LLVMValueRef *swizzled)
488 {
489    unsigned chan;
490
491    for (chan = 0; chan < 4; ++chan) {
492       swizzled[chan] = lp_build_swizzle_soa_channel(bld, unswizzled,
493                                                     swizzles[chan]);
494    }
495 }
496
497
498 /**
499  * Do an extended swizzle of a SoA vector inplace.
500  *
501  * @param bld         building context
502  * @param values      intput/output array with the 4 values
503  * @param swizzles    array of PIPE_SWIZZLE_*
504  */
505 void
506 lp_build_swizzle_soa_inplace(struct lp_build_context *bld,
507                              LLVMValueRef *values,
508                              const unsigned char swizzles[4])
509 {
510    LLVMValueRef unswizzled[4];
511    unsigned chan;
512
513    for (chan = 0; chan < 4; ++chan) {
514       unswizzled[chan] = values[chan];
515    }
516
517    lp_build_swizzle_soa(bld, unswizzled, swizzles, values);
518 }