• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2003 VMware, Inc.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * on the rights to use, copy, modify, merge, publish, distribute, sub
9  * license, and/or sell copies of the Software, and to permit persons to whom
10  * the Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * 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 NON-INFRINGEMENT.  IN NO EVENT SHALL
19  * VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
20  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22  * USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Keith Whitwell <keithw@vmware.com>
26  */
27 
28 
29 #include "pipe/p_config.h"
30 #include "pipe/p_compiler.h"
31 #include "util/u_memory.h"
32 #include "util/u_math.h"
33 #include "util/u_format.h"
34 
35 #include "translate.h"
36 
37 
38 #if (defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)) && !defined(PIPE_SUBSYSTEM_EMBEDDED)
39 
40 #include "rtasm/rtasm_cpu.h"
41 #include "rtasm/rtasm_x86sse.h"
42 
43 
44 #define X    0
45 #define Y    1
46 #define Z    2
47 #define W    3
48 
49 
50 struct translate_buffer
51 {
52    const void *base_ptr;
53    uintptr_t stride;
54    unsigned max_index;
55 };
56 
57 struct translate_buffer_variant
58 {
59    unsigned buffer_index;
60    unsigned instance_divisor;
61    void *ptr;                   /* updated either per vertex or per instance */
62 };
63 
64 
65 #define ELEMENT_BUFFER_INSTANCE_ID  1001
66 
67 #define NUM_CONSTS 7
68 
69 enum
70 {
71    CONST_IDENTITY,
72    CONST_INV_127,
73    CONST_INV_255,
74    CONST_INV_32767,
75    CONST_INV_65535,
76    CONST_INV_2147483647,
77    CONST_255
78 };
79 
80 #define C(v) {(float)(v), (float)(v), (float)(v), (float)(v)}
81 static float consts[NUM_CONSTS][4] = {
82    {0, 0, 0, 1},
83    C(1.0 / 127.0),
84    C(1.0 / 255.0),
85    C(1.0 / 32767.0),
86    C(1.0 / 65535.0),
87    C(1.0 / 2147483647.0),
88    C(255.0)
89 };
90 
91 #undef C
92 
93 struct translate_sse
94 {
95    struct translate translate;
96 
97    struct x86_function linear_func;
98    struct x86_function elt_func;
99    struct x86_function elt16_func;
100    struct x86_function elt8_func;
101    struct x86_function *func;
102 
103      PIPE_ALIGN_VAR(16) float consts[NUM_CONSTS][4];
104    int8_t reg_to_const[16];
105    int8_t const_to_reg[NUM_CONSTS];
106 
107    struct translate_buffer buffer[TRANSLATE_MAX_ATTRIBS];
108    unsigned nr_buffers;
109 
110    /* Multiple buffer variants can map to a single buffer. */
111    struct translate_buffer_variant buffer_variant[TRANSLATE_MAX_ATTRIBS];
112    unsigned nr_buffer_variants;
113 
114    /* Multiple elements can map to a single buffer variant. */
115    unsigned element_to_buffer_variant[TRANSLATE_MAX_ATTRIBS];
116 
117    boolean use_instancing;
118    unsigned instance_id;
119    unsigned start_instance;
120 
121    /* these are actually known values, but putting them in a struct
122     * like this is helpful to keep them in sync across the file.
123     */
124    struct x86_reg tmp_EAX;
125    struct x86_reg tmp2_EDX;
126    struct x86_reg src_ECX;
127    struct x86_reg idx_ESI;      /* either start+i or &elt[i] */
128    struct x86_reg machine_EDI;
129    struct x86_reg outbuf_EBX;
130    struct x86_reg count_EBP;    /* decrements to zero */
131 };
132 
133 
134 static int
get_offset(const void * a,const void * b)135 get_offset(const void *a, const void *b)
136 {
137    return (const char *) b - (const char *) a;
138 }
139 
140 
141 static struct x86_reg
get_const(struct translate_sse * p,unsigned id)142 get_const(struct translate_sse *p, unsigned id)
143 {
144    struct x86_reg reg;
145    unsigned i;
146 
147    if (p->const_to_reg[id] >= 0)
148       return x86_make_reg(file_XMM, p->const_to_reg[id]);
149 
150    for (i = 2; i < 8; ++i) {
151       if (p->reg_to_const[i] < 0)
152          break;
153    }
154 
155    /* TODO: be smarter here */
156    if (i == 8)
157       --i;
158 
159    reg = x86_make_reg(file_XMM, i);
160 
161    if (p->reg_to_const[i] >= 0)
162       p->const_to_reg[p->reg_to_const[i]] = -1;
163 
164    p->reg_to_const[i] = id;
165    p->const_to_reg[id] = i;
166 
167    /* TODO: this should happen outside the loop, if possible */
168    sse_movaps(p->func, reg,
169               x86_make_disp(p->machine_EDI,
170                             get_offset(p, &p->consts[id][0])));
171 
172    return reg;
173 }
174 
175 
176 /* load the data in a SSE2 register, padding with zeros */
177 static boolean
emit_load_sse2(struct translate_sse * p,struct x86_reg data,struct x86_reg src,unsigned size)178 emit_load_sse2(struct translate_sse *p,
179                struct x86_reg data, struct x86_reg src, unsigned size)
180 {
181    struct x86_reg tmpXMM = x86_make_reg(file_XMM, 1);
182    struct x86_reg tmp = p->tmp_EAX;
183    switch (size) {
184    case 1:
185       x86_movzx8(p->func, tmp, src);
186       sse2_movd(p->func, data, tmp);
187       break;
188    case 2:
189       x86_movzx16(p->func, tmp, src);
190       sse2_movd(p->func, data, tmp);
191       break;
192    case 3:
193       x86_movzx8(p->func, tmp, x86_make_disp(src, 2));
194       x86_shl_imm(p->func, tmp, 16);
195       x86_mov16(p->func, tmp, src);
196       sse2_movd(p->func, data, tmp);
197       break;
198    case 4:
199       sse2_movd(p->func, data, src);
200       break;
201    case 6:
202       sse2_movd(p->func, data, src);
203       x86_movzx16(p->func, tmp, x86_make_disp(src, 4));
204       sse2_movd(p->func, tmpXMM, tmp);
205       sse2_punpckldq(p->func, data, tmpXMM);
206       break;
207    case 8:
208       sse2_movq(p->func, data, src);
209       break;
210    case 12:
211       sse2_movq(p->func, data, src);
212       sse2_movd(p->func, tmpXMM, x86_make_disp(src, 8));
213       sse2_punpcklqdq(p->func, data, tmpXMM);
214       break;
215    case 16:
216       sse2_movdqu(p->func, data, src);
217       break;
218    default:
219       return FALSE;
220    }
221    return TRUE;
222 }
223 
224 
225 /* this value can be passed for the out_chans argument */
226 #define CHANNELS_0001 5
227 
228 
229 /* this function will load #chans float values, and will
230  * pad the register with zeroes at least up to out_chans.
231  *
232  * If out_chans is set to CHANNELS_0001, then the fourth
233  * value will be padded with 1. Only pass this value if
234  * chans < 4 or results are undefined.
235  */
236 static void
emit_load_float32(struct translate_sse * p,struct x86_reg data,struct x86_reg arg0,unsigned out_chans,unsigned chans)237 emit_load_float32(struct translate_sse *p, struct x86_reg data,
238                   struct x86_reg arg0, unsigned out_chans, unsigned chans)
239 {
240    switch (chans) {
241    case 1:
242       /* a 0 0 0
243        * a 0 0 1
244        */
245       sse_movss(p->func, data, arg0);
246       if (out_chans == CHANNELS_0001)
247          sse_orps(p->func, data, get_const(p, CONST_IDENTITY));
248       break;
249    case 2:
250       /* 0 0 0 1
251        * a b 0 1
252        */
253       if (out_chans == CHANNELS_0001)
254          sse_shufps(p->func, data, get_const(p, CONST_IDENTITY),
255                     SHUF(X, Y, Z, W));
256       else if (out_chans > 2)
257          sse_movlhps(p->func, data, get_const(p, CONST_IDENTITY));
258       sse_movlps(p->func, data, arg0);
259       break;
260    case 3:
261       /* Have to jump through some hoops:
262        *
263        * c 0 0 0
264        * c 0 0 1 if out_chans == CHANNELS_0001
265        * 0 0 c 0/1
266        * a b c 0/1
267        */
268       sse_movss(p->func, data, x86_make_disp(arg0, 8));
269       if (out_chans == CHANNELS_0001)
270          sse_shufps(p->func, data, get_const(p, CONST_IDENTITY),
271                     SHUF(X, Y, Z, W));
272       sse_shufps(p->func, data, data, SHUF(Y, Z, X, W));
273       sse_movlps(p->func, data, arg0);
274       break;
275    case 4:
276       sse_movups(p->func, data, arg0);
277       break;
278    }
279 }
280 
281 /* this function behaves like emit_load_float32, but loads
282    64-bit floating point numbers, converting them to 32-bit
283   ones */
284 static void
emit_load_float64to32(struct translate_sse * p,struct x86_reg data,struct x86_reg arg0,unsigned out_chans,unsigned chans)285 emit_load_float64to32(struct translate_sse *p, struct x86_reg data,
286                       struct x86_reg arg0, unsigned out_chans, unsigned chans)
287 {
288    struct x86_reg tmpXMM = x86_make_reg(file_XMM, 1);
289    switch (chans) {
290    case 1:
291       sse2_movsd(p->func, data, arg0);
292       if (out_chans > 1)
293          sse2_cvtpd2ps(p->func, data, data);
294       else
295          sse2_cvtsd2ss(p->func, data, data);
296       if (out_chans == CHANNELS_0001)
297          sse_shufps(p->func, data, get_const(p, CONST_IDENTITY),
298                     SHUF(X, Y, Z, W));
299       break;
300    case 2:
301       sse2_movupd(p->func, data, arg0);
302       sse2_cvtpd2ps(p->func, data, data);
303       if (out_chans == CHANNELS_0001)
304          sse_shufps(p->func, data, get_const(p, CONST_IDENTITY),
305                     SHUF(X, Y, Z, W));
306       else if (out_chans > 2)
307          sse_movlhps(p->func, data, get_const(p, CONST_IDENTITY));
308       break;
309    case 3:
310       sse2_movupd(p->func, data, arg0);
311       sse2_cvtpd2ps(p->func, data, data);
312       sse2_movsd(p->func, tmpXMM, x86_make_disp(arg0, 16));
313       if (out_chans > 3)
314          sse2_cvtpd2ps(p->func, tmpXMM, tmpXMM);
315       else
316          sse2_cvtsd2ss(p->func, tmpXMM, tmpXMM);
317       sse_movlhps(p->func, data, tmpXMM);
318       if (out_chans == CHANNELS_0001)
319          sse_orps(p->func, data, get_const(p, CONST_IDENTITY));
320       break;
321    case 4:
322       sse2_movupd(p->func, data, arg0);
323       sse2_cvtpd2ps(p->func, data, data);
324       sse2_movupd(p->func, tmpXMM, x86_make_disp(arg0, 16));
325       sse2_cvtpd2ps(p->func, tmpXMM, tmpXMM);
326       sse_movlhps(p->func, data, tmpXMM);
327       break;
328    }
329 }
330 
331 
332 static void
emit_mov64(struct translate_sse * p,struct x86_reg dst_gpr,struct x86_reg dst_xmm,struct x86_reg src_gpr,struct x86_reg src_xmm)333 emit_mov64(struct translate_sse *p, struct x86_reg dst_gpr,
334            struct x86_reg dst_xmm, struct x86_reg src_gpr,
335            struct x86_reg src_xmm)
336 {
337    if (x86_target(p->func) != X86_32)
338       x64_mov64(p->func, dst_gpr, src_gpr);
339    else {
340       /* TODO: when/on which CPUs is SSE2 actually better than SSE? */
341       if (x86_target_caps(p->func) & X86_SSE2)
342          sse2_movq(p->func, dst_xmm, src_xmm);
343       else
344          sse_movlps(p->func, dst_xmm, src_xmm);
345    }
346 }
347 
348 
349 static void
emit_load64(struct translate_sse * p,struct x86_reg dst_gpr,struct x86_reg dst_xmm,struct x86_reg src)350 emit_load64(struct translate_sse *p, struct x86_reg dst_gpr,
351             struct x86_reg dst_xmm, struct x86_reg src)
352 {
353    emit_mov64(p, dst_gpr, dst_xmm, src, src);
354 }
355 
356 
357 static void
emit_store64(struct translate_sse * p,struct x86_reg dst,struct x86_reg src_gpr,struct x86_reg src_xmm)358 emit_store64(struct translate_sse *p, struct x86_reg dst,
359              struct x86_reg src_gpr, struct x86_reg src_xmm)
360 {
361    emit_mov64(p, dst, dst, src_gpr, src_xmm);
362 }
363 
364 
365 static void
emit_mov128(struct translate_sse * p,struct x86_reg dst,struct x86_reg src)366 emit_mov128(struct translate_sse *p, struct x86_reg dst, struct x86_reg src)
367 {
368    if (x86_target_caps(p->func) & X86_SSE2)
369       sse2_movdqu(p->func, dst, src);
370    else
371       sse_movups(p->func, dst, src);
372 }
373 
374 
375 /* TODO: this uses unaligned accesses liberally, which is great on Nehalem,
376  * but may or may not be good on older processors
377  * TODO: may perhaps want to use non-temporal stores here if possible
378  */
379 static void
emit_memcpy(struct translate_sse * p,struct x86_reg dst,struct x86_reg src,unsigned size)380 emit_memcpy(struct translate_sse *p, struct x86_reg dst, struct x86_reg src,
381             unsigned size)
382 {
383    struct x86_reg dataXMM = x86_make_reg(file_XMM, 0);
384    struct x86_reg dataXMM2 = x86_make_reg(file_XMM, 1);
385    struct x86_reg dataGPR = p->tmp_EAX;
386    struct x86_reg dataGPR2 = p->tmp2_EDX;
387 
388    if (size < 8) {
389       switch (size) {
390       case 1:
391          x86_mov8(p->func, dataGPR, src);
392          x86_mov8(p->func, dst, dataGPR);
393          break;
394       case 2:
395          x86_mov16(p->func, dataGPR, src);
396          x86_mov16(p->func, dst, dataGPR);
397          break;
398       case 3:
399          x86_mov16(p->func, dataGPR, src);
400          x86_mov8(p->func, dataGPR2, x86_make_disp(src, 2));
401          x86_mov16(p->func, dst, dataGPR);
402          x86_mov8(p->func, x86_make_disp(dst, 2), dataGPR2);
403          break;
404       case 4:
405          x86_mov(p->func, dataGPR, src);
406          x86_mov(p->func, dst, dataGPR);
407          break;
408       case 6:
409          x86_mov(p->func, dataGPR, src);
410          x86_mov16(p->func, dataGPR2, x86_make_disp(src, 4));
411          x86_mov(p->func, dst, dataGPR);
412          x86_mov16(p->func, x86_make_disp(dst, 4), dataGPR2);
413          break;
414       }
415    }
416    else if (!(x86_target_caps(p->func) & X86_SSE)) {
417       unsigned i = 0;
418       assert((size & 3) == 0);
419       for (i = 0; i < size; i += 4) {
420          x86_mov(p->func, dataGPR, x86_make_disp(src, i));
421          x86_mov(p->func, x86_make_disp(dst, i), dataGPR);
422       }
423    }
424    else {
425       switch (size) {
426       case 8:
427          emit_load64(p, dataGPR, dataXMM, src);
428          emit_store64(p, dst, dataGPR, dataXMM);
429          break;
430       case 12:
431          emit_load64(p, dataGPR2, dataXMM, src);
432          x86_mov(p->func, dataGPR, x86_make_disp(src, 8));
433          emit_store64(p, dst, dataGPR2, dataXMM);
434          x86_mov(p->func, x86_make_disp(dst, 8), dataGPR);
435          break;
436       case 16:
437          emit_mov128(p, dataXMM, src);
438          emit_mov128(p, dst, dataXMM);
439          break;
440       case 24:
441          emit_mov128(p, dataXMM, src);
442          emit_load64(p, dataGPR, dataXMM2, x86_make_disp(src, 16));
443          emit_mov128(p, dst, dataXMM);
444          emit_store64(p, x86_make_disp(dst, 16), dataGPR, dataXMM2);
445          break;
446       case 32:
447          emit_mov128(p, dataXMM, src);
448          emit_mov128(p, dataXMM2, x86_make_disp(src, 16));
449          emit_mov128(p, dst, dataXMM);
450          emit_mov128(p, x86_make_disp(dst, 16), dataXMM2);
451          break;
452       default:
453          assert(0);
454       }
455    }
456 }
457 
458 static boolean
translate_attr_convert(struct translate_sse * p,const struct translate_element * a,struct x86_reg src,struct x86_reg dst)459 translate_attr_convert(struct translate_sse *p,
460                        const struct translate_element *a,
461                        struct x86_reg src, struct x86_reg dst)
462 {
463    const struct util_format_description *input_desc =
464       util_format_description(a->input_format);
465    const struct util_format_description *output_desc =
466       util_format_description(a->output_format);
467    unsigned i;
468    boolean id_swizzle = TRUE;
469    unsigned swizzle[4] =
470       { PIPE_SWIZZLE_NONE, PIPE_SWIZZLE_NONE,
471         PIPE_SWIZZLE_NONE, PIPE_SWIZZLE_NONE };
472    unsigned needed_chans = 0;
473    unsigned imms[2] = { 0, 0x3f800000 };
474 
475    if (a->output_format == PIPE_FORMAT_NONE
476        || a->input_format == PIPE_FORMAT_NONE)
477       return FALSE;
478 
479    if (input_desc->channel[0].size & 7)
480       return FALSE;
481 
482    if (input_desc->colorspace != output_desc->colorspace)
483       return FALSE;
484 
485    for (i = 1; i < input_desc->nr_channels; ++i) {
486       if (memcmp
487           (&input_desc->channel[i], &input_desc->channel[0],
488            sizeof(input_desc->channel[0])))
489          return FALSE;
490    }
491 
492    for (i = 1; i < output_desc->nr_channels; ++i) {
493       if (memcmp
494           (&output_desc->channel[i], &output_desc->channel[0],
495            sizeof(output_desc->channel[0]))) {
496          return FALSE;
497       }
498    }
499 
500    for (i = 0; i < output_desc->nr_channels; ++i) {
501       if (output_desc->swizzle[i] < 4)
502          swizzle[output_desc->swizzle[i]] = input_desc->swizzle[i];
503    }
504 
505    if ((x86_target_caps(p->func) & X86_SSE) &&
506        (0 || a->output_format == PIPE_FORMAT_R32_FLOAT
507         || a->output_format == PIPE_FORMAT_R32G32_FLOAT
508         || a->output_format == PIPE_FORMAT_R32G32B32_FLOAT
509         || a->output_format == PIPE_FORMAT_R32G32B32A32_FLOAT)) {
510       struct x86_reg dataXMM = x86_make_reg(file_XMM, 0);
511 
512       for (i = 0; i < output_desc->nr_channels; ++i) {
513          if (swizzle[i] == PIPE_SWIZZLE_0
514              && i >= input_desc->nr_channels)
515             swizzle[i] = i;
516       }
517 
518       for (i = 0; i < output_desc->nr_channels; ++i) {
519          if (swizzle[i] < 4)
520             needed_chans = MAX2(needed_chans, swizzle[i] + 1);
521          if (swizzle[i] < PIPE_SWIZZLE_0 && swizzle[i] != i)
522             id_swizzle = FALSE;
523       }
524 
525       if (needed_chans > 0) {
526          switch (input_desc->channel[0].type) {
527          case UTIL_FORMAT_TYPE_UNSIGNED:
528             if (!(x86_target_caps(p->func) & X86_SSE2))
529                return FALSE;
530             emit_load_sse2(p, dataXMM, src,
531                            input_desc->channel[0].size *
532                            input_desc->nr_channels >> 3);
533 
534             /* TODO: add support for SSE4.1 pmovzx */
535             switch (input_desc->channel[0].size) {
536             case 8:
537                /* TODO: this may be inefficient due to get_identity() being
538                 *  used both as a float and integer register.
539                 */
540                sse2_punpcklbw(p->func, dataXMM, get_const(p, CONST_IDENTITY));
541                sse2_punpcklbw(p->func, dataXMM, get_const(p, CONST_IDENTITY));
542                break;
543             case 16:
544                sse2_punpcklwd(p->func, dataXMM, get_const(p, CONST_IDENTITY));
545                break;
546             case 32:           /* we lose precision here */
547                sse2_psrld_imm(p->func, dataXMM, 1);
548                break;
549             default:
550                return FALSE;
551             }
552             sse2_cvtdq2ps(p->func, dataXMM, dataXMM);
553             if (input_desc->channel[0].normalized) {
554                struct x86_reg factor;
555                switch (input_desc->channel[0].size) {
556                case 8:
557                   factor = get_const(p, CONST_INV_255);
558                   break;
559                case 16:
560                   factor = get_const(p, CONST_INV_65535);
561                   break;
562                case 32:
563                   factor = get_const(p, CONST_INV_2147483647);
564                   break;
565                default:
566                   assert(0);
567                   factor.disp = 0;
568                   factor.file = 0;
569                   factor.idx = 0;
570                   factor.mod = 0;
571                   break;
572                }
573                sse_mulps(p->func, dataXMM, factor);
574             }
575             else if (input_desc->channel[0].size == 32)
576                /* compensate for the bit we threw away to fit u32 into s32 */
577                sse_addps(p->func, dataXMM, dataXMM);
578             break;
579          case UTIL_FORMAT_TYPE_SIGNED:
580             if (!(x86_target_caps(p->func) & X86_SSE2))
581                return FALSE;
582             emit_load_sse2(p, dataXMM, src,
583                            input_desc->channel[0].size *
584                            input_desc->nr_channels >> 3);
585 
586             /* TODO: add support for SSE4.1 pmovsx */
587             switch (input_desc->channel[0].size) {
588             case 8:
589                sse2_punpcklbw(p->func, dataXMM, dataXMM);
590                sse2_punpcklbw(p->func, dataXMM, dataXMM);
591                sse2_psrad_imm(p->func, dataXMM, 24);
592                break;
593             case 16:
594                sse2_punpcklwd(p->func, dataXMM, dataXMM);
595                sse2_psrad_imm(p->func, dataXMM, 16);
596                break;
597             case 32:           /* we lose precision here */
598                break;
599             default:
600                return FALSE;
601             }
602             sse2_cvtdq2ps(p->func, dataXMM, dataXMM);
603             if (input_desc->channel[0].normalized) {
604                struct x86_reg factor;
605                switch (input_desc->channel[0].size) {
606                case 8:
607                   factor = get_const(p, CONST_INV_127);
608                   break;
609                case 16:
610                   factor = get_const(p, CONST_INV_32767);
611                   break;
612                case 32:
613                   factor = get_const(p, CONST_INV_2147483647);
614                   break;
615                default:
616                   assert(0);
617                   factor.disp = 0;
618                   factor.file = 0;
619                   factor.idx = 0;
620                   factor.mod = 0;
621                   break;
622                }
623                sse_mulps(p->func, dataXMM, factor);
624             }
625             break;
626 
627             break;
628          case UTIL_FORMAT_TYPE_FLOAT:
629             if (input_desc->channel[0].size != 32
630                 && input_desc->channel[0].size != 64) {
631                return FALSE;
632             }
633             if (swizzle[3] == PIPE_SWIZZLE_1
634                 && input_desc->nr_channels <= 3) {
635                swizzle[3] = PIPE_SWIZZLE_W;
636                needed_chans = CHANNELS_0001;
637             }
638             switch (input_desc->channel[0].size) {
639             case 32:
640                emit_load_float32(p, dataXMM, src, needed_chans,
641                                  input_desc->nr_channels);
642                break;
643             case 64:           /* we lose precision here */
644                if (!(x86_target_caps(p->func) & X86_SSE2))
645                   return FALSE;
646                emit_load_float64to32(p, dataXMM, src, needed_chans,
647                                      input_desc->nr_channels);
648                break;
649             default:
650                return FALSE;
651             }
652             break;
653          default:
654             return FALSE;
655          }
656 
657          if (!id_swizzle) {
658             sse_shufps(p->func, dataXMM, dataXMM,
659                        SHUF(swizzle[0], swizzle[1], swizzle[2], swizzle[3]));
660          }
661       }
662 
663       if (output_desc->nr_channels >= 4
664           && swizzle[0] < PIPE_SWIZZLE_0
665           && swizzle[1] < PIPE_SWIZZLE_0
666           && swizzle[2] < PIPE_SWIZZLE_0
667           && swizzle[3] < PIPE_SWIZZLE_0) {
668          sse_movups(p->func, dst, dataXMM);
669       }
670       else {
671          if (output_desc->nr_channels >= 2
672              && swizzle[0] < PIPE_SWIZZLE_0
673              && swizzle[1] < PIPE_SWIZZLE_0) {
674             sse_movlps(p->func, dst, dataXMM);
675          }
676          else {
677             if (swizzle[0] < PIPE_SWIZZLE_0) {
678                sse_movss(p->func, dst, dataXMM);
679             }
680             else {
681                x86_mov_imm(p->func, dst,
682                            imms[swizzle[0] - PIPE_SWIZZLE_0]);
683             }
684 
685             if (output_desc->nr_channels >= 2) {
686                if (swizzle[1] < PIPE_SWIZZLE_0) {
687                   sse_shufps(p->func, dataXMM, dataXMM, SHUF(1, 1, 2, 3));
688                   sse_movss(p->func, x86_make_disp(dst, 4), dataXMM);
689                }
690                else {
691                   x86_mov_imm(p->func, x86_make_disp(dst, 4),
692                               imms[swizzle[1] - PIPE_SWIZZLE_0]);
693                }
694             }
695          }
696 
697          if (output_desc->nr_channels >= 3) {
698             if (output_desc->nr_channels >= 4
699                 && swizzle[2] < PIPE_SWIZZLE_0
700                 && swizzle[3] < PIPE_SWIZZLE_0) {
701                sse_movhps(p->func, x86_make_disp(dst, 8), dataXMM);
702             }
703             else {
704                if (swizzle[2] < PIPE_SWIZZLE_0) {
705                   sse_shufps(p->func, dataXMM, dataXMM, SHUF(2, 2, 2, 3));
706                   sse_movss(p->func, x86_make_disp(dst, 8), dataXMM);
707                }
708                else {
709                   x86_mov_imm(p->func, x86_make_disp(dst, 8),
710                               imms[swizzle[2] - PIPE_SWIZZLE_0]);
711                }
712 
713                if (output_desc->nr_channels >= 4) {
714                   if (swizzle[3] < PIPE_SWIZZLE_0) {
715                      sse_shufps(p->func, dataXMM, dataXMM, SHUF(3, 3, 3, 3));
716                      sse_movss(p->func, x86_make_disp(dst, 12), dataXMM);
717                   }
718                   else {
719                      x86_mov_imm(p->func, x86_make_disp(dst, 12),
720                                  imms[swizzle[3] - PIPE_SWIZZLE_0]);
721                   }
722                }
723             }
724          }
725       }
726       return TRUE;
727    }
728    else if ((x86_target_caps(p->func) & X86_SSE2)
729             && input_desc->channel[0].size == 8
730             && output_desc->channel[0].size == 16
731             && output_desc->channel[0].normalized ==
732             input_desc->channel[0].normalized &&
733             (0 || (input_desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED
734                    && output_desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED)
735              || (input_desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED
736                  && output_desc->channel[0].type == UTIL_FORMAT_TYPE_SIGNED)
737              || (input_desc->channel[0].type == UTIL_FORMAT_TYPE_SIGNED
738                  && output_desc->channel[0].type == UTIL_FORMAT_TYPE_SIGNED))) {
739       struct x86_reg dataXMM = x86_make_reg(file_XMM, 0);
740       struct x86_reg tmpXMM = x86_make_reg(file_XMM, 1);
741       struct x86_reg tmp = p->tmp_EAX;
742       unsigned imms[2] = { 0, 1 };
743 
744       for (i = 0; i < output_desc->nr_channels; ++i) {
745          if (swizzle[i] == PIPE_SWIZZLE_0
746              && i >= input_desc->nr_channels) {
747             swizzle[i] = i;
748          }
749       }
750 
751       for (i = 0; i < output_desc->nr_channels; ++i) {
752          if (swizzle[i] < 4)
753             needed_chans = MAX2(needed_chans, swizzle[i] + 1);
754          if (swizzle[i] < PIPE_SWIZZLE_0 && swizzle[i] != i)
755             id_swizzle = FALSE;
756       }
757 
758       if (needed_chans > 0) {
759          emit_load_sse2(p, dataXMM, src,
760                         input_desc->channel[0].size *
761                         input_desc->nr_channels >> 3);
762 
763          switch (input_desc->channel[0].type) {
764          case UTIL_FORMAT_TYPE_UNSIGNED:
765             if (input_desc->channel[0].normalized) {
766                sse2_punpcklbw(p->func, dataXMM, dataXMM);
767                if (output_desc->channel[0].type == UTIL_FORMAT_TYPE_SIGNED)
768                   sse2_psrlw_imm(p->func, dataXMM, 1);
769             }
770             else
771                sse2_punpcklbw(p->func, dataXMM, get_const(p, CONST_IDENTITY));
772             break;
773          case UTIL_FORMAT_TYPE_SIGNED:
774             if (input_desc->channel[0].normalized) {
775                sse2_movq(p->func, tmpXMM, get_const(p, CONST_IDENTITY));
776                sse2_punpcklbw(p->func, tmpXMM, dataXMM);
777                sse2_psllw_imm(p->func, dataXMM, 9);
778                sse2_psrlw_imm(p->func, dataXMM, 8);
779                sse2_por(p->func, tmpXMM, dataXMM);
780                sse2_psrlw_imm(p->func, dataXMM, 7);
781                sse2_por(p->func, tmpXMM, dataXMM);
782                {
783                   struct x86_reg t = dataXMM;
784                   dataXMM = tmpXMM;
785                   tmpXMM = t;
786                }
787             }
788             else {
789                sse2_punpcklbw(p->func, dataXMM, dataXMM);
790                sse2_psraw_imm(p->func, dataXMM, 8);
791             }
792             break;
793          default:
794             assert(0);
795          }
796 
797          if (output_desc->channel[0].normalized)
798             imms[1] =
799                (output_desc->channel[0].type ==
800                 UTIL_FORMAT_TYPE_UNSIGNED) ? 0xffff : 0x7ffff;
801 
802          if (!id_swizzle)
803             sse2_pshuflw(p->func, dataXMM, dataXMM,
804                          (swizzle[0] & 3) | ((swizzle[1] & 3) << 2) |
805                          ((swizzle[2] & 3) << 4) | ((swizzle[3] & 3) << 6));
806       }
807 
808       if (output_desc->nr_channels >= 4
809           && swizzle[0] < PIPE_SWIZZLE_0
810           && swizzle[1] < PIPE_SWIZZLE_0
811           && swizzle[2] < PIPE_SWIZZLE_0
812           && swizzle[3] < PIPE_SWIZZLE_0) {
813          sse2_movq(p->func, dst, dataXMM);
814       }
815       else {
816          if (swizzle[0] < PIPE_SWIZZLE_0) {
817             if (output_desc->nr_channels >= 2
818                 && swizzle[1] < PIPE_SWIZZLE_0) {
819                sse2_movd(p->func, dst, dataXMM);
820             }
821             else {
822                sse2_movd(p->func, tmp, dataXMM);
823                x86_mov16(p->func, dst, tmp);
824                if (output_desc->nr_channels >= 2)
825                   x86_mov16_imm(p->func, x86_make_disp(dst, 2),
826                                 imms[swizzle[1] - PIPE_SWIZZLE_0]);
827             }
828          }
829          else {
830             if (output_desc->nr_channels >= 2
831                 && swizzle[1] >= PIPE_SWIZZLE_0) {
832                x86_mov_imm(p->func, dst,
833                            (imms[swizzle[1] - PIPE_SWIZZLE_0] << 16) |
834                            imms[swizzle[0] - PIPE_SWIZZLE_0]);
835             }
836             else {
837                x86_mov16_imm(p->func, dst,
838                              imms[swizzle[0] - PIPE_SWIZZLE_0]);
839                if (output_desc->nr_channels >= 2) {
840                   sse2_movd(p->func, tmp, dataXMM);
841                   x86_shr_imm(p->func, tmp, 16);
842                   x86_mov16(p->func, x86_make_disp(dst, 2), tmp);
843                }
844             }
845          }
846 
847          if (output_desc->nr_channels >= 3) {
848             if (swizzle[2] < PIPE_SWIZZLE_0) {
849                if (output_desc->nr_channels >= 4
850                    && swizzle[3] < PIPE_SWIZZLE_0) {
851                   sse2_psrlq_imm(p->func, dataXMM, 32);
852                   sse2_movd(p->func, x86_make_disp(dst, 4), dataXMM);
853                }
854                else {
855                   sse2_psrlq_imm(p->func, dataXMM, 32);
856                   sse2_movd(p->func, tmp, dataXMM);
857                   x86_mov16(p->func, x86_make_disp(dst, 4), tmp);
858                   if (output_desc->nr_channels >= 4) {
859                      x86_mov16_imm(p->func, x86_make_disp(dst, 6),
860                                    imms[swizzle[3] - PIPE_SWIZZLE_0]);
861                   }
862                }
863             }
864             else {
865                if (output_desc->nr_channels >= 4
866                    && swizzle[3] >= PIPE_SWIZZLE_0) {
867                   x86_mov_imm(p->func, x86_make_disp(dst, 4),
868                               (imms[swizzle[3] - PIPE_SWIZZLE_0] << 16)
869                               | imms[swizzle[2] - PIPE_SWIZZLE_0]);
870                }
871                else {
872                   x86_mov16_imm(p->func, x86_make_disp(dst, 4),
873                                 imms[swizzle[2] - PIPE_SWIZZLE_0]);
874 
875                   if (output_desc->nr_channels >= 4) {
876                      sse2_psrlq_imm(p->func, dataXMM, 48);
877                      sse2_movd(p->func, tmp, dataXMM);
878                      x86_mov16(p->func, x86_make_disp(dst, 6), tmp);
879                   }
880                }
881             }
882          }
883       }
884       return TRUE;
885    }
886    else if (!memcmp(&output_desc->channel[0], &input_desc->channel[0],
887                     sizeof(output_desc->channel[0]))) {
888       struct x86_reg tmp = p->tmp_EAX;
889       unsigned i;
890 
891       if (input_desc->channel[0].size == 8 && input_desc->nr_channels == 4
892           && output_desc->nr_channels == 4
893           && swizzle[0] == PIPE_SWIZZLE_W
894           && swizzle[1] == PIPE_SWIZZLE_Z
895           && swizzle[2] == PIPE_SWIZZLE_Y
896           && swizzle[3] == PIPE_SWIZZLE_X) {
897          /* TODO: support movbe */
898          x86_mov(p->func, tmp, src);
899          x86_bswap(p->func, tmp);
900          x86_mov(p->func, dst, tmp);
901          return TRUE;
902       }
903 
904       for (i = 0; i < output_desc->nr_channels; ++i) {
905          switch (output_desc->channel[0].size) {
906          case 8:
907             if (swizzle[i] >= PIPE_SWIZZLE_0) {
908                unsigned v = 0;
909                if (swizzle[i] == PIPE_SWIZZLE_1) {
910                   switch (output_desc->channel[0].type) {
911                   case UTIL_FORMAT_TYPE_UNSIGNED:
912                      v = output_desc->channel[0].normalized ? 0xff : 1;
913                      break;
914                   case UTIL_FORMAT_TYPE_SIGNED:
915                      v = output_desc->channel[0].normalized ? 0x7f : 1;
916                      break;
917                   default:
918                      return FALSE;
919                   }
920                }
921                x86_mov8_imm(p->func, x86_make_disp(dst, i * 1), v);
922             }
923             else {
924                x86_mov8(p->func, tmp, x86_make_disp(src, swizzle[i] * 1));
925                x86_mov8(p->func, x86_make_disp(dst, i * 1), tmp);
926             }
927             break;
928          case 16:
929             if (swizzle[i] >= PIPE_SWIZZLE_0) {
930                unsigned v = 0;
931                if (swizzle[i] == PIPE_SWIZZLE_1) {
932                   switch (output_desc->channel[1].type) {
933                   case UTIL_FORMAT_TYPE_UNSIGNED:
934                      v = output_desc->channel[1].normalized ? 0xffff : 1;
935                      break;
936                   case UTIL_FORMAT_TYPE_SIGNED:
937                      v = output_desc->channel[1].normalized ? 0x7fff : 1;
938                      break;
939                   case UTIL_FORMAT_TYPE_FLOAT:
940                      v = 0x3c00;
941                      break;
942                   default:
943                      return FALSE;
944                   }
945                }
946                x86_mov16_imm(p->func, x86_make_disp(dst, i * 2), v);
947             }
948             else if (swizzle[i] == PIPE_SWIZZLE_0) {
949                x86_mov16_imm(p->func, x86_make_disp(dst, i * 2), 0);
950             }
951             else {
952                x86_mov16(p->func, tmp, x86_make_disp(src, swizzle[i] * 2));
953                x86_mov16(p->func, x86_make_disp(dst, i * 2), tmp);
954             }
955             break;
956          case 32:
957             if (swizzle[i] >= PIPE_SWIZZLE_0) {
958                unsigned v = 0;
959                if (swizzle[i] == PIPE_SWIZZLE_1) {
960                   switch (output_desc->channel[1].type) {
961                   case UTIL_FORMAT_TYPE_UNSIGNED:
962                      v = output_desc->channel[1].normalized ? 0xffffffff : 1;
963                      break;
964                   case UTIL_FORMAT_TYPE_SIGNED:
965                      v = output_desc->channel[1].normalized ? 0x7fffffff : 1;
966                      break;
967                   case UTIL_FORMAT_TYPE_FLOAT:
968                      v = 0x3f800000;
969                      break;
970                   default:
971                      return FALSE;
972                   }
973                }
974                x86_mov_imm(p->func, x86_make_disp(dst, i * 4), v);
975             }
976             else {
977                x86_mov(p->func, tmp, x86_make_disp(src, swizzle[i] * 4));
978                x86_mov(p->func, x86_make_disp(dst, i * 4), tmp);
979             }
980             break;
981          case 64:
982             if (swizzle[i] >= PIPE_SWIZZLE_0) {
983                unsigned l = 0;
984                unsigned h = 0;
985                if (swizzle[i] == PIPE_SWIZZLE_1) {
986                   switch (output_desc->channel[1].type) {
987                   case UTIL_FORMAT_TYPE_UNSIGNED:
988                      h = output_desc->channel[1].normalized ? 0xffffffff : 0;
989                      l = output_desc->channel[1].normalized ? 0xffffffff : 1;
990                      break;
991                   case UTIL_FORMAT_TYPE_SIGNED:
992                      h = output_desc->channel[1].normalized ? 0x7fffffff : 0;
993                      l = output_desc->channel[1].normalized ? 0xffffffff : 1;
994                      break;
995                   case UTIL_FORMAT_TYPE_FLOAT:
996                      h = 0x3ff00000;
997                      l = 0;
998                      break;
999                   default:
1000                      return FALSE;
1001                   }
1002                }
1003                x86_mov_imm(p->func, x86_make_disp(dst, i * 8), l);
1004                x86_mov_imm(p->func, x86_make_disp(dst, i * 8 + 4), h);
1005             }
1006             else {
1007                if (x86_target_caps(p->func) & X86_SSE) {
1008                   struct x86_reg tmpXMM = x86_make_reg(file_XMM, 0);
1009                   emit_load64(p, tmp, tmpXMM,
1010                               x86_make_disp(src, swizzle[i] * 8));
1011                   emit_store64(p, x86_make_disp(dst, i * 8), tmp, tmpXMM);
1012                }
1013                else {
1014                   x86_mov(p->func, tmp, x86_make_disp(src, swizzle[i] * 8));
1015                   x86_mov(p->func, x86_make_disp(dst, i * 8), tmp);
1016                   x86_mov(p->func, tmp,
1017                           x86_make_disp(src, swizzle[i] * 8 + 4));
1018                   x86_mov(p->func, x86_make_disp(dst, i * 8 + 4), tmp);
1019                }
1020             }
1021             break;
1022          default:
1023             return FALSE;
1024          }
1025       }
1026       return TRUE;
1027    }
1028    /* special case for draw's EMIT_4UB (RGBA) and EMIT_4UB_BGRA */
1029    else if ((x86_target_caps(p->func) & X86_SSE2) &&
1030             a->input_format == PIPE_FORMAT_R32G32B32A32_FLOAT &&
1031             (0 || a->output_format == PIPE_FORMAT_B8G8R8A8_UNORM
1032              || a-> output_format == PIPE_FORMAT_R8G8B8A8_UNORM)) {
1033       struct x86_reg dataXMM = x86_make_reg(file_XMM, 0);
1034 
1035       /* load */
1036       sse_movups(p->func, dataXMM, src);
1037 
1038       if (a->output_format == PIPE_FORMAT_B8G8R8A8_UNORM) {
1039          sse_shufps(p->func, dataXMM, dataXMM, SHUF(2, 1, 0, 3));
1040       }
1041 
1042       /* scale by 255.0 */
1043       sse_mulps(p->func, dataXMM, get_const(p, CONST_255));
1044 
1045       /* pack and emit */
1046       sse2_cvtps2dq(p->func, dataXMM, dataXMM);
1047       sse2_packssdw(p->func, dataXMM, dataXMM);
1048       sse2_packuswb(p->func, dataXMM, dataXMM);
1049       sse2_movd(p->func, dst, dataXMM);
1050 
1051       return TRUE;
1052    }
1053 
1054    return FALSE;
1055 }
1056 
1057 
1058 static boolean
translate_attr(struct translate_sse * p,const struct translate_element * a,struct x86_reg src,struct x86_reg dst)1059 translate_attr(struct translate_sse *p,
1060                const struct translate_element *a,
1061                struct x86_reg src, struct x86_reg dst)
1062 {
1063    if (a->input_format == a->output_format) {
1064       emit_memcpy(p, dst, src, util_format_get_stride(a->input_format, 1));
1065       return TRUE;
1066    }
1067 
1068    return translate_attr_convert(p, a, src, dst);
1069 }
1070 
1071 
1072 static boolean
init_inputs(struct translate_sse * p,unsigned index_size)1073 init_inputs(struct translate_sse *p, unsigned index_size)
1074 {
1075    unsigned i;
1076    struct x86_reg instance_id =
1077       x86_make_disp(p->machine_EDI, get_offset(p, &p->instance_id));
1078    struct x86_reg start_instance =
1079       x86_make_disp(p->machine_EDI, get_offset(p, &p->start_instance));
1080 
1081    for (i = 0; i < p->nr_buffer_variants; i++) {
1082       struct translate_buffer_variant *variant = &p->buffer_variant[i];
1083       struct translate_buffer *buffer = &p->buffer[variant->buffer_index];
1084 
1085       if (!index_size || variant->instance_divisor) {
1086          struct x86_reg buf_max_index =
1087             x86_make_disp(p->machine_EDI, get_offset(p, &buffer->max_index));
1088          struct x86_reg buf_stride =
1089             x86_make_disp(p->machine_EDI, get_offset(p, &buffer->stride));
1090          struct x86_reg buf_ptr =
1091             x86_make_disp(p->machine_EDI, get_offset(p, &variant->ptr));
1092          struct x86_reg buf_base_ptr =
1093             x86_make_disp(p->machine_EDI, get_offset(p, &buffer->base_ptr));
1094          struct x86_reg elt = p->idx_ESI;
1095          struct x86_reg tmp_EAX = p->tmp_EAX;
1096 
1097          /* Calculate pointer to first attrib:
1098           *   base_ptr + stride * index, where index depends on instance divisor
1099           */
1100          if (variant->instance_divisor) {
1101             struct x86_reg tmp_EDX = p->tmp2_EDX;
1102 
1103             /* Start with instance = instance_id
1104              * which is true if divisor is 1.
1105              */
1106             x86_mov(p->func, tmp_EAX, instance_id);
1107 
1108             if (variant->instance_divisor != 1) {
1109                struct x86_reg tmp_ECX = p->src_ECX;
1110 
1111                /* TODO: Add x86_shr() to rtasm and use it whenever
1112                 *       instance divisor is power of two.
1113                 */
1114                x86_xor(p->func, tmp_EDX, tmp_EDX);
1115                x86_mov_reg_imm(p->func, tmp_ECX, variant->instance_divisor);
1116                x86_div(p->func, tmp_ECX);       /* EAX = EDX:EAX / ECX */
1117             }
1118 
1119             /* instance = (instance_id / divisor) + start_instance
1120              */
1121             x86_mov(p->func, tmp_EDX, start_instance);
1122             x86_add(p->func, tmp_EAX, tmp_EDX);
1123 
1124             /* XXX we need to clamp the index here too, but to a
1125              * per-array max value, not the draw->pt.max_index value
1126              * that's being given to us via translate->set_buffer().
1127              */
1128          }
1129          else {
1130             x86_mov(p->func, tmp_EAX, elt);
1131 
1132             /* Clamp to max_index
1133              */
1134             x86_cmp(p->func, tmp_EAX, buf_max_index);
1135             x86_cmovcc(p->func, tmp_EAX, buf_max_index, cc_AE);
1136          }
1137 
1138          x86_mov(p->func, p->tmp2_EDX, buf_stride);
1139          x64_rexw(p->func);
1140          x86_imul(p->func, tmp_EAX, p->tmp2_EDX);
1141          x64_rexw(p->func);
1142          x86_add(p->func, tmp_EAX, buf_base_ptr);
1143 
1144          x86_cmp(p->func, p->count_EBP, p->tmp_EAX);
1145 
1146          /* In the linear case, keep the buffer pointer instead of the
1147           * index number.
1148           */
1149          if (!index_size && p->nr_buffer_variants == 1) {
1150             x64_rexw(p->func);
1151             x86_mov(p->func, elt, tmp_EAX);
1152          }
1153          else {
1154             x64_rexw(p->func);
1155             x86_mov(p->func, buf_ptr, tmp_EAX);
1156          }
1157       }
1158    }
1159 
1160    return TRUE;
1161 }
1162 
1163 
1164 static struct x86_reg
get_buffer_ptr(struct translate_sse * p,unsigned index_size,unsigned var_idx,struct x86_reg elt)1165 get_buffer_ptr(struct translate_sse *p,
1166                unsigned index_size, unsigned var_idx, struct x86_reg elt)
1167 {
1168    if (var_idx == ELEMENT_BUFFER_INSTANCE_ID) {
1169       return x86_make_disp(p->machine_EDI, get_offset(p, &p->instance_id));
1170    }
1171    if (!index_size && p->nr_buffer_variants == 1) {
1172       return p->idx_ESI;
1173    }
1174    else if (!index_size || p->buffer_variant[var_idx].instance_divisor) {
1175       struct x86_reg ptr = p->src_ECX;
1176       struct x86_reg buf_ptr =
1177          x86_make_disp(p->machine_EDI,
1178                        get_offset(p, &p->buffer_variant[var_idx].ptr));
1179 
1180       x64_rexw(p->func);
1181       x86_mov(p->func, ptr, buf_ptr);
1182       return ptr;
1183    }
1184    else {
1185       struct x86_reg ptr = p->src_ECX;
1186       const struct translate_buffer_variant *variant =
1187          &p->buffer_variant[var_idx];
1188       struct x86_reg buf_stride =
1189          x86_make_disp(p->machine_EDI,
1190                        get_offset(p, &p->buffer[variant->buffer_index].stride));
1191       struct x86_reg buf_base_ptr =
1192          x86_make_disp(p->machine_EDI,
1193                   get_offset(p, &p->buffer[variant->buffer_index].base_ptr));
1194       struct x86_reg buf_max_index =
1195          x86_make_disp(p->machine_EDI,
1196                   get_offset(p, &p->buffer[variant->buffer_index].max_index));
1197 
1198       /* Calculate pointer to current attrib:
1199        */
1200       switch (index_size) {
1201       case 1:
1202          x86_movzx8(p->func, ptr, elt);
1203          break;
1204       case 2:
1205          x86_movzx16(p->func, ptr, elt);
1206          break;
1207       case 4:
1208          x86_mov(p->func, ptr, elt);
1209          break;
1210       }
1211 
1212       /* Clamp to max_index
1213        */
1214       x86_cmp(p->func, ptr, buf_max_index);
1215       x86_cmovcc(p->func, ptr, buf_max_index, cc_AE);
1216 
1217       x86_mov(p->func, p->tmp2_EDX, buf_stride);
1218       x64_rexw(p->func);
1219       x86_imul(p->func, ptr, p->tmp2_EDX);
1220       x64_rexw(p->func);
1221       x86_add(p->func, ptr, buf_base_ptr);
1222       return ptr;
1223    }
1224 }
1225 
1226 
1227 static boolean
incr_inputs(struct translate_sse * p,unsigned index_size)1228 incr_inputs(struct translate_sse *p, unsigned index_size)
1229 {
1230    if (!index_size && p->nr_buffer_variants == 1) {
1231       const unsigned buffer_index = p->buffer_variant[0].buffer_index;
1232       struct x86_reg stride =
1233          x86_make_disp(p->machine_EDI,
1234                        get_offset(p, &p->buffer[buffer_index].stride));
1235 
1236       if (p->buffer_variant[0].instance_divisor == 0) {
1237          x64_rexw(p->func);
1238          x86_add(p->func, p->idx_ESI, stride);
1239          sse_prefetchnta(p->func, x86_make_disp(p->idx_ESI, 192));
1240       }
1241    }
1242    else if (!index_size) {
1243       unsigned i;
1244 
1245       /* Is this worthwhile??
1246        */
1247       for (i = 0; i < p->nr_buffer_variants; i++) {
1248          struct translate_buffer_variant *variant = &p->buffer_variant[i];
1249          struct x86_reg buf_ptr = x86_make_disp(p->machine_EDI,
1250                                                 get_offset(p, &variant->ptr));
1251       struct x86_reg buf_stride =
1252          x86_make_disp(p->machine_EDI,
1253                        get_offset(p, &p->buffer[variant->buffer_index].stride));
1254 
1255          if (variant->instance_divisor == 0) {
1256             x86_mov(p->func, p->tmp_EAX, buf_stride);
1257             x64_rexw(p->func);
1258             x86_add(p->func, p->tmp_EAX, buf_ptr);
1259             if (i == 0)
1260                sse_prefetchnta(p->func, x86_make_disp(p->tmp_EAX, 192));
1261             x64_rexw(p->func);
1262             x86_mov(p->func, buf_ptr, p->tmp_EAX);
1263          }
1264       }
1265    }
1266    else {
1267       x64_rexw(p->func);
1268       x86_lea(p->func, p->idx_ESI, x86_make_disp(p->idx_ESI, index_size));
1269    }
1270 
1271    return TRUE;
1272 }
1273 
1274 
1275 /* Build run( struct translate *machine,
1276  *            unsigned start,
1277  *            unsigned count,
1278  *            void *output_buffer )
1279  * or
1280  *  run_elts( struct translate *machine,
1281  *            unsigned *elts,
1282  *            unsigned count,
1283  *            void *output_buffer )
1284  *
1285  *  Lots of hardcoding
1286  *
1287  * EAX -- pointer to current output vertex
1288  * ECX -- pointer to current attribute
1289  *
1290  */
1291 static boolean
build_vertex_emit(struct translate_sse * p,struct x86_function * func,unsigned index_size)1292 build_vertex_emit(struct translate_sse *p,
1293                   struct x86_function *func, unsigned index_size)
1294 {
1295    int fixup, label;
1296    unsigned j;
1297 
1298    memset(p->reg_to_const, 0xff, sizeof(p->reg_to_const));
1299    memset(p->const_to_reg, 0xff, sizeof(p->const_to_reg));
1300 
1301    p->tmp_EAX = x86_make_reg(file_REG32, reg_AX);
1302    p->idx_ESI = x86_make_reg(file_REG32, reg_SI);
1303    p->outbuf_EBX = x86_make_reg(file_REG32, reg_BX);
1304    p->machine_EDI = x86_make_reg(file_REG32, reg_DI);
1305    p->count_EBP = x86_make_reg(file_REG32, reg_BP);
1306    p->tmp2_EDX = x86_make_reg(file_REG32, reg_DX);
1307    p->src_ECX = x86_make_reg(file_REG32, reg_CX);
1308 
1309    p->func = func;
1310 
1311    x86_init_func(p->func);
1312 
1313    if (x86_target(p->func) == X86_64_WIN64_ABI) {
1314       /* the ABI guarantees a 16-byte aligned 32-byte "shadow space"
1315        * above the return address
1316        */
1317       sse2_movdqa(p->func, x86_make_disp(x86_make_reg(file_REG32, reg_SP), 8),
1318                   x86_make_reg(file_XMM, 6));
1319       sse2_movdqa(p->func,
1320                   x86_make_disp(x86_make_reg(file_REG32, reg_SP), 24),
1321                   x86_make_reg(file_XMM, 7));
1322    }
1323 
1324    x86_push(p->func, p->outbuf_EBX);
1325    x86_push(p->func, p->count_EBP);
1326 
1327    /* on non-Win64 x86-64, these are already in the right registers */
1328    if (x86_target(p->func) != X86_64_STD_ABI) {
1329       x86_push(p->func, p->machine_EDI);
1330       x86_push(p->func, p->idx_ESI);
1331 
1332       if (x86_target(p->func) != X86_32) {
1333          x64_mov64(p->func, p->machine_EDI, x86_fn_arg(p->func, 1));
1334          x64_mov64(p->func, p->idx_ESI, x86_fn_arg(p->func, 2));
1335       }
1336       else {
1337          x86_mov(p->func, p->machine_EDI, x86_fn_arg(p->func, 1));
1338          x86_mov(p->func, p->idx_ESI, x86_fn_arg(p->func, 2));
1339       }
1340    }
1341 
1342    x86_mov(p->func, p->count_EBP, x86_fn_arg(p->func, 3));
1343 
1344    if (x86_target(p->func) != X86_32)
1345       x64_mov64(p->func, p->outbuf_EBX, x86_fn_arg(p->func, 6));
1346    else
1347       x86_mov(p->func, p->outbuf_EBX, x86_fn_arg(p->func, 6));
1348 
1349    /* Load instance ID.
1350     */
1351    if (p->use_instancing) {
1352       x86_mov(p->func, p->tmp2_EDX, x86_fn_arg(p->func, 4));
1353       x86_mov(p->func,
1354               x86_make_disp(p->machine_EDI,
1355                             get_offset(p, &p->start_instance)), p->tmp2_EDX);
1356 
1357       x86_mov(p->func, p->tmp_EAX, x86_fn_arg(p->func, 5));
1358       x86_mov(p->func,
1359               x86_make_disp(p->machine_EDI, get_offset(p, &p->instance_id)),
1360               p->tmp_EAX);
1361    }
1362 
1363    /* Get vertex count, compare to zero
1364     */
1365    x86_xor(p->func, p->tmp_EAX, p->tmp_EAX);
1366    x86_cmp(p->func, p->count_EBP, p->tmp_EAX);
1367    fixup = x86_jcc_forward(p->func, cc_E);
1368 
1369    /* always load, needed or not:
1370     */
1371    init_inputs(p, index_size);
1372 
1373    /* Note address for loop jump
1374     */
1375    label = x86_get_label(p->func);
1376    {
1377       struct x86_reg elt = !index_size ? p->idx_ESI : x86_deref(p->idx_ESI);
1378       int last_variant = -1;
1379       struct x86_reg vb;
1380 
1381       for (j = 0; j < p->translate.key.nr_elements; j++) {
1382          const struct translate_element *a = &p->translate.key.element[j];
1383          unsigned variant = p->element_to_buffer_variant[j];
1384 
1385          /* Figure out source pointer address:
1386           */
1387          if (variant != last_variant) {
1388             last_variant = variant;
1389             vb = get_buffer_ptr(p, index_size, variant, elt);
1390          }
1391 
1392          if (!translate_attr(p, a,
1393                              x86_make_disp(vb, a->input_offset),
1394                              x86_make_disp(p->outbuf_EBX, a->output_offset)))
1395             return FALSE;
1396       }
1397 
1398       /* Next output vertex:
1399        */
1400       x64_rexw(p->func);
1401       x86_lea(p->func, p->outbuf_EBX,
1402               x86_make_disp(p->outbuf_EBX, p->translate.key.output_stride));
1403 
1404       /* Incr index
1405        */
1406       incr_inputs(p, index_size);
1407    }
1408 
1409    /* decr count, loop if not zero
1410     */
1411    x86_dec(p->func, p->count_EBP);
1412    x86_jcc(p->func, cc_NZ, label);
1413 
1414    /* Exit mmx state?
1415     */
1416    if (p->func->need_emms)
1417       mmx_emms(p->func);
1418 
1419    /* Land forward jump here:
1420     */
1421    x86_fixup_fwd_jump(p->func, fixup);
1422 
1423    /* Pop regs and return
1424     */
1425    if (x86_target(p->func) != X86_64_STD_ABI) {
1426       x86_pop(p->func, p->idx_ESI);
1427       x86_pop(p->func, p->machine_EDI);
1428    }
1429 
1430    x86_pop(p->func, p->count_EBP);
1431    x86_pop(p->func, p->outbuf_EBX);
1432 
1433    if (x86_target(p->func) == X86_64_WIN64_ABI) {
1434       sse2_movdqa(p->func, x86_make_reg(file_XMM, 6),
1435                   x86_make_disp(x86_make_reg(file_REG32, reg_SP), 8));
1436       sse2_movdqa(p->func, x86_make_reg(file_XMM, 7),
1437                   x86_make_disp(x86_make_reg(file_REG32, reg_SP), 24));
1438    }
1439    x86_ret(p->func);
1440 
1441    return TRUE;
1442 }
1443 
1444 
1445 static void
translate_sse_set_buffer(struct translate * translate,unsigned buf,const void * ptr,unsigned stride,unsigned max_index)1446 translate_sse_set_buffer(struct translate *translate,
1447                          unsigned buf,
1448                          const void *ptr, unsigned stride, unsigned max_index)
1449 {
1450    struct translate_sse *p = (struct translate_sse *) translate;
1451 
1452    if (buf < p->nr_buffers) {
1453       p->buffer[buf].base_ptr = (char *) ptr;
1454       p->buffer[buf].stride = stride;
1455       p->buffer[buf].max_index = max_index;
1456    }
1457 
1458    if (0)
1459       debug_printf("%s %d/%d: %p %d\n",
1460                    __FUNCTION__, buf, p->nr_buffers, ptr, stride);
1461 }
1462 
1463 
1464 static void
translate_sse_release(struct translate * translate)1465 translate_sse_release(struct translate *translate)
1466 {
1467    struct translate_sse *p = (struct translate_sse *) translate;
1468 
1469    x86_release_func(&p->elt8_func);
1470    x86_release_func(&p->elt16_func);
1471    x86_release_func(&p->elt_func);
1472    x86_release_func(&p->linear_func);
1473 
1474    os_free_aligned(p);
1475 }
1476 
1477 
1478 struct translate *
translate_sse2_create(const struct translate_key * key)1479 translate_sse2_create(const struct translate_key *key)
1480 {
1481    struct translate_sse *p = NULL;
1482    unsigned i;
1483 
1484    /* this is misnamed, it actually refers to whether rtasm is enabled or not */
1485    if (!rtasm_cpu_has_sse())
1486       goto fail;
1487 
1488    p = os_malloc_aligned(sizeof(struct translate_sse), 16);
1489    if (!p)
1490       goto fail;
1491 
1492    memset(p, 0, sizeof(*p));
1493    memcpy(p->consts, consts, sizeof(consts));
1494 
1495    p->translate.key = *key;
1496    p->translate.release = translate_sse_release;
1497    p->translate.set_buffer = translate_sse_set_buffer;
1498 
1499    assert(key->nr_elements <= TRANSLATE_MAX_ATTRIBS);
1500 
1501    for (i = 0; i < key->nr_elements; i++) {
1502       if (key->element[i].type == TRANSLATE_ELEMENT_NORMAL) {
1503          unsigned j;
1504 
1505          p->nr_buffers =
1506             MAX2(p->nr_buffers, key->element[i].input_buffer + 1);
1507 
1508          if (key->element[i].instance_divisor) {
1509             p->use_instancing = TRUE;
1510          }
1511 
1512          /*
1513           * Map vertex element to vertex buffer variant.
1514           */
1515          for (j = 0; j < p->nr_buffer_variants; j++) {
1516             if (p->buffer_variant[j].buffer_index ==
1517                 key->element[i].input_buffer
1518                 && p->buffer_variant[j].instance_divisor ==
1519                 key->element[i].instance_divisor) {
1520                break;
1521             }
1522          }
1523          if (j == p->nr_buffer_variants) {
1524             p->buffer_variant[j].buffer_index = key->element[i].input_buffer;
1525             p->buffer_variant[j].instance_divisor =
1526                key->element[i].instance_divisor;
1527             p->nr_buffer_variants++;
1528          }
1529          p->element_to_buffer_variant[i] = j;
1530       }
1531       else {
1532          assert(key->element[i].type == TRANSLATE_ELEMENT_INSTANCE_ID);
1533 
1534          p->element_to_buffer_variant[i] = ELEMENT_BUFFER_INSTANCE_ID;
1535       }
1536    }
1537 
1538    if (0)
1539       debug_printf("nr_buffers: %d\n", p->nr_buffers);
1540 
1541    if (!build_vertex_emit(p, &p->linear_func, 0))
1542       goto fail;
1543 
1544    if (!build_vertex_emit(p, &p->elt_func, 4))
1545       goto fail;
1546 
1547    if (!build_vertex_emit(p, &p->elt16_func, 2))
1548       goto fail;
1549 
1550    if (!build_vertex_emit(p, &p->elt8_func, 1))
1551       goto fail;
1552 
1553    p->translate.run = (run_func) x86_get_func(&p->linear_func);
1554    if (p->translate.run == NULL)
1555       goto fail;
1556 
1557    p->translate.run_elts = (run_elts_func) x86_get_func(&p->elt_func);
1558    if (p->translate.run_elts == NULL)
1559       goto fail;
1560 
1561    p->translate.run_elts16 = (run_elts16_func) x86_get_func(&p->elt16_func);
1562    if (p->translate.run_elts16 == NULL)
1563       goto fail;
1564 
1565    p->translate.run_elts8 = (run_elts8_func) x86_get_func(&p->elt8_func);
1566    if (p->translate.run_elts8 == NULL)
1567       goto fail;
1568 
1569    return &p->translate;
1570 
1571  fail:
1572    if (p)
1573       translate_sse_release(&p->translate);
1574 
1575    return NULL;
1576 }
1577 
1578 
1579 #else
1580 
1581 struct translate *
translate_sse2_create(const struct translate_key * key)1582 translate_sse2_create(const struct translate_key *key)
1583 {
1584    return NULL;
1585 }
1586 
1587 #endif
1588