2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 * \file t_vb_arb_program_sse.c
28 * Translate simplified vertex_program representation to x86/SSE/SSE2
29 * machine code using mesa's rtasm runtime assembler.
31 * \author Keith Whitwell
39 #include "arbprogparse.h"
41 #include "math/m_matrix.h"
42 #include "math/m_translate.h"
43 #include "t_context.h"
44 #include "t_vb_arbprogram.h"
46 #if defined(USE_SSE_ASM)
48 #include "x86/rtasm/x86sse.h"
49 #include "x86/common_x86_asm.h"
59 * EAX - point to 'm->File[0]'
60 * ECX - point to 'm->File[3]'
73 _mesa_printf("x86 translation failed in %s\n", __FUNCTION__); \
78 struct x86_function func
;
79 struct arb_vp_machine
*m
;
97 static INLINE GLboolean
eq( struct x86_reg a
,
100 return (a
.file
== b
.file
&&
108 static struct x86_reg
get_reg_ptr(GLuint file
,
115 reg
= x86_make_reg(file_REG32
, reg_AX
);
116 assert(idx
!= REG_UNDEF
);
118 case FILE_STATE_PARAM
:
119 reg
= x86_make_reg(file_REG32
, reg_CX
);
125 return x86_make_disp(reg
, 16 * idx
);
129 static void spill( struct compilation
*cp
, GLuint idx
)
131 struct x86_reg oldval
= get_reg_ptr(cp
->xmm
[idx
].file
,
134 assert(cp
->xmm
[idx
].dirty
);
135 sse_movups(&cp
->func
, oldval
, x86_make_reg(file_XMM
, idx
));
136 cp
->xmm
[idx
].dirty
= 0;
139 static struct x86_reg
get_xmm_reg( struct compilation
*cp
)
144 for (i
= 0; i
< 8; i
++)
145 if (cp
->xmm
[i
].last_used
< cp
->xmm
[oldest
].last_used
)
148 /* Need to write out the old value?
150 if (cp
->xmm
[oldest
].dirty
)
153 assert(cp
->xmm
[oldest
].last_used
!= cp
->insn_counter
);
155 cp
->xmm
[oldest
].file
= FILE_REG
;
156 cp
->xmm
[oldest
].idx
= REG_UNDEF
;
157 cp
->xmm
[oldest
].last_used
= cp
->insn_counter
;
158 return x86_make_reg(file_XMM
, oldest
);
164 static struct x86_reg
get_dst_reg( struct compilation
*cp
,
165 GLuint file
, GLuint idx
)
170 /* Invalidate any old copy of this register in XMM0-7. Don't reuse
171 * as this may be one of the arguments.
173 for (i
= 0; i
< 8; i
++) {
174 if (cp
->xmm
[i
].file
== file
&& cp
->xmm
[i
].idx
== idx
) {
175 cp
->xmm
[i
].file
= FILE_REG
;
176 cp
->xmm
[i
].idx
= REG_UNDEF
;
177 cp
->xmm
[i
].dirty
= 0;
182 reg
= get_xmm_reg( cp
);
183 cp
->xmm
[reg
.idx
].file
= file
;
184 cp
->xmm
[reg
.idx
].idx
= idx
;
185 cp
->xmm
[reg
.idx
].dirty
= 1;
190 /* Return an XMM reg if the argument is resident, otherwise return a
191 * base+offset pointer to the saved value.
193 static struct x86_reg
get_arg( struct compilation
*cp
, GLuint file
, GLuint idx
)
197 for (i
= 0; i
< 8; i
++) {
198 if (cp
->xmm
[i
].file
== file
&&
199 cp
->xmm
[i
].idx
== idx
) {
200 cp
->xmm
[i
].last_used
= cp
->insn_counter
;
201 return x86_make_reg(file_XMM
, i
);
205 return get_reg_ptr(file
, idx
);
208 static void emit_pshufd( struct compilation
*cp
,
214 sse2_pshufd(&cp
->func
, dst
, arg0
, shuf
);
219 sse_movups(&cp
->func
, dst
, arg0
);
221 sse_shufps(&cp
->func
, dst
, dst
, shuf
);
227 /* Perform a reduced swizzle.
229 static GLboolean
emit_RSW( struct compilation
*cp
, union instruction op
)
231 struct x86_reg arg0
= get_arg(cp
, op
.rsw
.file0
, op
.rsw
.idx0
);
232 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.rsw
.dst
);
233 GLuint swz
= op
.rsw
.swz
;
234 GLuint neg
= op
.rsw
.neg
;
236 emit_pshufd(cp
, dst
, arg0
, swz
);
239 struct x86_reg negs
= get_arg(cp
, FILE_REG
, REG_SWZ
);
240 struct x86_reg tmp
= get_xmm_reg(cp
);
242 * Use neg as arg to pshufd
245 emit_pshufd(cp
, tmp
, negs
,
246 SHUF((neg
& 1) ? 1 : 0,
250 sse_mulps(&cp
->func
, dst
, tmp
);
256 /* Used to implement write masking. This and most of the other instructions
257 * here would be easier to implement if there had been a translation
258 * to a 2 argument format (dst/arg0, arg1) at the shader level before
259 * attempting to translate to x86/sse code.
261 /* Hmm. I went back to MSK from SEL to make things easier -- was that just BS?
263 static GLboolean
emit_MSK( struct compilation
*cp
, union instruction op
)
265 struct x86_reg arg
= get_arg(cp
, op
.msk
.file
, op
.msk
.idx
);
266 struct x86_reg dst0
= get_arg(cp
, FILE_REG
, op
.msk
.dst
);
267 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.msk
.dst
);
269 sse_movups(&cp
->func
, dst
, dst0
);
271 switch (op
.msk
.mask
) {
276 if (arg
.file
== file_XMM
) {
277 sse_movss(&cp
->func
, dst
, arg
);
280 struct x86_reg tmp
= get_xmm_reg(cp
);
281 sse_movss(&cp
->func
, tmp
, arg
);
282 sse_movss(&cp
->func
, dst
, tmp
);
287 struct x86_reg tmp
= get_xmm_reg(cp
);
288 emit_pshufd(cp
, dst
, dst
, SHUF(Y
, X
, Z
, W
));
289 emit_pshufd(cp
, tmp
, arg
, SHUF(Y
, X
, Z
, W
));
290 sse_movss(&cp
->func
, dst
, tmp
);
291 emit_pshufd(cp
, dst
, dst
, SHUF(Y
, X
, Z
, W
));
296 struct x86_reg tmp
= get_xmm_reg(cp
);
297 emit_pshufd(cp
, dst
, dst
, SHUF(Z
, Y
, X
, W
));
298 emit_pshufd(cp
, tmp
, arg
, SHUF(Z
, Y
, X
, W
));
299 sse_movss(&cp
->func
, dst
, tmp
);
300 emit_pshufd(cp
, dst
, dst
, SHUF(Z
, Y
, X
, W
));
305 struct x86_reg tmp
= get_xmm_reg(cp
);
306 emit_pshufd(cp
, dst
, dst
, SHUF(W
, Y
, Z
, X
));
307 emit_pshufd(cp
, tmp
, arg
, SHUF(W
, Y
, Z
, X
));
308 sse_movss(&cp
->func
, dst
, tmp
);
309 emit_pshufd(cp
, dst
, dst
, SHUF(W
, Y
, Z
, X
));
314 sse_shufps(&cp
->func
, dst
, arg
, SHUF(X
, Y
, Z
, W
));
318 struct x86_reg tmp
= get_xmm_reg(cp
);
319 sse_movups(&cp
->func
, tmp
, dst
);
320 sse_movups(&cp
->func
, dst
, arg
);
321 sse_shufps(&cp
->func
, dst
, tmp
, SHUF(X
, Y
, Z
, W
));
325 case WRITEMASK_YZW
: {
326 struct x86_reg tmp
= get_xmm_reg(cp
);
327 sse_movss(&cp
->func
, tmp
, dst
);
328 sse_movups(&cp
->func
, dst
, arg
);
329 sse_movss(&cp
->func
, dst
, tmp
);
334 sse_movups(&cp
->func
, dst
, arg
);
342 /* The catchall implementation:
345 /* make full width bitmask in tmp
352 struct x86_reg negs
= get_arg(cp
, FILE_REG
, REG_NEGS
);
353 emit_pshufd(cp
, tmp
, negs
,
354 SHUF((op
.msk
.mask
& 1) ? 2 : 0,
355 (op
.msk
.mask
& 2) ? 2 : 0,
356 (op
.msk
.mask
& 4) ? 2 : 0,
357 (op
.msk
.mask
& 8) ? 2 : 0));
358 sse_mulps(&cp
->func
, dst
, tmp
);
368 static GLboolean
emit_PRT( struct compilation
*cp
, union instruction op
)
375 * The traditional instructions. All operate on internal registers
376 * and ignore write masks and swizzling issues.
379 static GLboolean
emit_ABS( struct compilation
*cp
, union instruction op
)
381 struct x86_reg arg0
= get_arg(cp
, op
.alu
.file0
, op
.alu
.idx0
);
382 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.alu
.dst
);
383 struct x86_reg neg
= get_reg_ptr(FILE_REG
, REG_NEG
);
385 sse_movups(&cp
->func
, dst
, arg0
);
386 sse_mulps(&cp
->func
, dst
, neg
);
387 sse_maxps(&cp
->func
, dst
, arg0
);
391 static GLboolean
emit_ADD( struct compilation
*cp
, union instruction op
)
393 struct x86_reg arg0
= get_arg(cp
, op
.alu
.file0
, op
.alu
.idx0
);
394 struct x86_reg arg1
= get_arg(cp
, op
.alu
.file1
, op
.alu
.idx1
);
395 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.alu
.dst
);
397 sse_movups(&cp
->func
, dst
, arg0
);
398 sse_addps(&cp
->func
, dst
, arg1
);
403 /* The dotproduct instructions don't really do that well in sse:
405 static GLboolean
emit_DP3( struct compilation
*cp
, union instruction op
)
407 struct x86_reg arg0
= get_arg(cp
, op
.alu
.file0
, op
.alu
.idx0
);
408 struct x86_reg arg1
= get_arg(cp
, op
.alu
.file1
, op
.alu
.idx1
);
409 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.alu
.dst
);
410 struct x86_reg tmp
= get_xmm_reg(cp
);
412 sse_movups(&cp
->func
, dst
, arg0
);
413 sse_mulps(&cp
->func
, dst
, arg1
);
415 /* Now the hard bit: sum the first 3 values:
417 sse_movhlps(&cp
->func
, tmp
, dst
);
418 sse_addss(&cp
->func
, dst
, tmp
); /* a*x+c*z, b*y, ?, ? */
419 emit_pshufd(cp
, tmp
, dst
, SHUF(Y
,X
,W
,Z
));
420 sse_addss(&cp
->func
, dst
, tmp
);
421 sse_shufps(&cp
->func
, dst
, dst
, SHUF(X
, X
, X
, X
));
427 static GLboolean
emit_DP4( struct compilation
*cp
, union instruction op
)
429 struct x86_reg arg0
= get_arg(cp
, op
.alu
.file0
, op
.alu
.idx0
);
430 struct x86_reg arg1
= get_arg(cp
, op
.alu
.file1
, op
.alu
.idx1
);
431 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.alu
.dst
);
432 struct x86_reg tmp
= get_xmm_reg(cp
);
434 sse_movups(&cp
->func
, dst
, arg0
);
435 sse_mulps(&cp
->func
, dst
, arg1
);
437 /* Now the hard bit: sum the values:
439 sse_movhlps(&cp
->func
, tmp
, dst
);
440 sse_addps(&cp
->func
, dst
, tmp
); /* a*x+c*z, b*y+d*w, a*x+c*z, b*y+d*w */
441 emit_pshufd(cp
, tmp
, dst
, SHUF(Y
,X
,W
,Z
));
442 sse_addss(&cp
->func
, dst
, tmp
);
443 sse_shufps(&cp
->func
, dst
, dst
, SHUF(X
, X
, X
, X
));
447 static GLboolean
emit_DPH( struct compilation
*cp
, union instruction op
)
449 /* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
450 /* struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1); */
451 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.alu
.dst
);
453 /* dst[0] = (arg0[0] * arg1[0] + */
454 /* arg0[1] * arg1[1] + */
455 /* arg0[2] * arg1[2] + */
456 /* 1.0 * arg1[3]); */
458 sse_shufps(&cp
->func
, dst
, dst
, SHUF(X
, X
, X
, X
));
462 static GLboolean
emit_DST( struct compilation
*cp
, union instruction op
)
464 /* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
465 /* struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1); */
466 /* struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst); */
468 /* dst[0] = 1.0 * 1.0F; */
469 /* dst[1] = arg0[1] * arg1[1]; */
470 /* dst[2] = arg0[2] * 1.0; */
471 /* dst[3] = 1.0 * arg1[3]; */
477 static GLboolean
emit_EX2( struct compilation
*cp
, union instruction op
)
479 /* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
480 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.alu
.dst
);
482 /* dst[0] = (GLfloat)RoughApproxPow2(arg0[0]); */
483 sse_shufps(&cp
->func
, dst
, dst
, SHUF(X
, X
, X
, X
));
487 static GLboolean
emit_EXP( struct compilation
*cp
, union instruction op
)
489 /* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
490 /* struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst); */
492 /* GLfloat tmp = arg0[0]; */
493 /* GLfloat flr_tmp = FLOORF(tmp); */
494 /* dst[0] = (GLfloat) (1 << (int)flr_tmp); */
495 /* dst[1] = tmp - flr_tmp; */
496 /* dst[2] = RoughApproxPow2(tmp); */
501 static GLboolean
emit_FLR( struct compilation
*cp
, union instruction op
)
503 /* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
504 /* struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst); */
506 /* dst[0] = FLOORF(arg0[0]); */
507 /* dst[1] = FLOORF(arg0[1]); */
508 /* dst[2] = FLOORF(arg0[2]); */
509 /* dst[3] = FLOORF(arg0[3]); */
513 static GLboolean
emit_FRC( struct compilation
*cp
, union instruction op
)
515 /* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
516 /* struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst); */
518 /* dst[0] = arg0[0] - FLOORF(arg0[0]); */
519 /* dst[1] = arg0[1] - FLOORF(arg0[1]); */
520 /* dst[2] = arg0[2] - FLOORF(arg0[2]); */
521 /* dst[3] = arg0[3] - FLOORF(arg0[3]); */
525 static GLboolean
emit_LG2( struct compilation
*cp
, union instruction op
)
527 /* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
528 /* struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst); */
530 /* dst[0] = RoughApproxLog2(arg0[0]); */
532 /* sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X)); */
538 static GLboolean
emit_LIT( struct compilation
*cp
, union instruction op
)
540 /* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
541 /* struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst); */
543 /* const GLfloat epsilon = 1.0F / 256.0F; */
544 /* GLfloat tmp[4]; */
546 /* tmp[0] = MAX2(arg0[0], 0.0F); */
547 /* tmp[1] = MAX2(arg0[1], 0.0F); */
548 /* tmp[3] = CLAMP(arg0[3], -(128.0F - epsilon), (128.0F - epsilon)); */
551 /* dst[1] = tmp[0]; */
552 /* dst[2] = (tmp[0] > 0.0) ? RoughApproxPower(tmp[1], tmp[3]) : 0.0F; */
558 static GLboolean
emit_LOG( struct compilation
*cp
, union instruction op
)
560 /* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
561 /* struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst); */
563 /* GLfloat tmp = FABSF(arg0[0]); */
565 /* GLfloat mantissa = FREXPF(tmp, &exponent); */
566 /* dst[0] = (GLfloat) (exponent - 1); */
567 /* dst[1] = 2.0 * mantissa; // map [.5, 1) -> [1, 2) */
568 /* dst[2] = dst[0] + LOG2(dst[1]); */
573 static GLboolean
emit_MAX( struct compilation
*cp
, union instruction op
)
575 struct x86_reg arg0
= get_arg(cp
, op
.alu
.file0
, op
.alu
.idx0
);
576 struct x86_reg arg1
= get_arg(cp
, op
.alu
.file1
, op
.alu
.idx1
);
577 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.alu
.dst
);
579 sse_movups(&cp
->func
, dst
, arg0
);
580 sse_maxps(&cp
->func
, dst
, arg1
);
585 static GLboolean
emit_MIN( struct compilation
*cp
, union instruction op
)
587 struct x86_reg arg0
= get_arg(cp
, op
.alu
.file0
, op
.alu
.idx0
);
588 struct x86_reg arg1
= get_arg(cp
, op
.alu
.file1
, op
.alu
.idx1
);
589 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.alu
.dst
);
591 sse_movups(&cp
->func
, dst
, arg0
);
592 sse_minps(&cp
->func
, dst
, arg1
);
596 static GLboolean
emit_MOV( struct compilation
*cp
, union instruction op
)
598 struct x86_reg arg0
= get_arg(cp
, op
.alu
.file0
, op
.alu
.idx0
);
599 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.alu
.dst
);
601 sse_movups(&cp
->func
, dst
, arg0
);
605 static GLboolean
emit_MUL( struct compilation
*cp
, union instruction op
)
607 struct x86_reg arg0
= get_arg(cp
, op
.alu
.file0
, op
.alu
.idx0
);
608 struct x86_reg arg1
= get_arg(cp
, op
.alu
.file1
, op
.alu
.idx1
);
609 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.alu
.dst
);
611 sse_movups(&cp
->func
, dst
, arg0
);
612 sse_mulps(&cp
->func
, dst
, arg1
);
617 static GLboolean
emit_POW( struct compilation
*cp
, union instruction op
)
619 /* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
620 /* struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1); */
621 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.alu
.dst
);
623 /* dst[0] = (GLfloat)RoughApproxPower(arg0[0], arg1[0]); */
625 sse_shufps(&cp
->func
, dst
, dst
, SHUF(X
, X
, X
, X
));
629 static GLboolean
emit_REL( struct compilation
*cp
, union instruction op
)
631 /* GLuint idx = (op.alu.idx0 + (GLint)cp->File[0][REG_ADDR][0]) & (MAX_NV_VERTEX_PROGRAM_PARAMS-1); */
632 /* GLuint idx = 0; */
633 /* struct x86_reg arg0 = get_arg(cp, op.alu.file0, idx); */
634 /* struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst); */
636 /* dst[0] = arg0[0]; */
637 /* dst[1] = arg0[1]; */
638 /* dst[2] = arg0[2]; */
639 /* dst[3] = arg0[3]; */
644 static GLboolean
emit_RCP( struct compilation
*cp
, union instruction op
)
646 struct x86_reg arg0
= get_arg(cp
, op
.alu
.file0
, op
.alu
.idx0
);
647 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.alu
.dst
);
650 sse2_rcpss(&cp
->func
, dst
, arg0
);
653 struct x86_reg ones
= get_reg_ptr(FILE_REG
, REG_ONES
);
654 sse_movss(&cp
->func
, dst
, ones
);
655 sse_divss(&cp
->func
, dst
, arg0
);
658 sse_shufps(&cp
->func
, dst
, dst
, SHUF(X
, X
, X
, X
));
662 static GLboolean
emit_RSQ( struct compilation
*cp
, union instruction op
)
664 struct x86_reg arg0
= get_arg(cp
, op
.alu
.file0
, op
.alu
.idx0
);
665 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.alu
.dst
);
667 sse_rsqrtss(&cp
->func
, dst
, arg0
);
668 sse_shufps(&cp
->func
, dst
, dst
, SHUF(X
, X
, X
, X
));
673 static GLboolean
emit_SGE( struct compilation
*cp
, union instruction op
)
675 struct x86_reg arg0
= get_arg(cp
, op
.alu
.file0
, op
.alu
.idx0
);
676 struct x86_reg arg1
= get_arg(cp
, op
.alu
.file1
, op
.alu
.idx1
);
677 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.alu
.dst
);
678 struct x86_reg ones
= get_reg_ptr(FILE_REG
, REG_ONES
);
680 sse_movups(&cp
->func
, dst
, arg0
);
681 sse_cmpps(&cp
->func
, dst
, arg1
, cc_NotLessThan
);
682 sse_andps(&cp
->func
, dst
, ones
);
687 static GLboolean
emit_SLT( struct compilation
*cp
, union instruction op
)
689 struct x86_reg arg0
= get_arg(cp
, op
.alu
.file0
, op
.alu
.idx0
);
690 struct x86_reg arg1
= get_arg(cp
, op
.alu
.file1
, op
.alu
.idx1
);
691 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.alu
.dst
);
692 struct x86_reg ones
= get_reg_ptr(FILE_REG
, REG_ONES
);
694 sse_movups(&cp
->func
, dst
, arg0
);
695 sse_cmpps(&cp
->func
, dst
, arg1
, cc_LessThan
);
696 sse_andps(&cp
->func
, dst
, ones
);
700 static GLboolean
emit_SUB( struct compilation
*cp
, union instruction op
)
702 struct x86_reg arg0
= get_arg(cp
, op
.alu
.file0
, op
.alu
.idx0
);
703 struct x86_reg arg1
= get_arg(cp
, op
.alu
.file1
, op
.alu
.idx1
);
704 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.alu
.dst
);
706 sse_movups(&cp
->func
, dst
, arg0
);
707 sse_subps(&cp
->func
, dst
, arg1
);
712 static GLboolean
emit_XPD( struct compilation
*cp
, union instruction op
)
714 struct x86_reg arg0
= get_arg(cp
, op
.alu
.file0
, op
.alu
.idx0
);
715 struct x86_reg arg1
= get_arg(cp
, op
.alu
.file1
, op
.alu
.idx1
);
716 struct x86_reg dst
= get_dst_reg(cp
, FILE_REG
, op
.alu
.dst
);
717 struct x86_reg tmp0
= get_xmm_reg(cp
);
718 struct x86_reg tmp1
= get_xmm_reg(cp
);
720 /* Could avoid tmp0, tmp1 if we overwrote arg0, arg1. Need a way
721 * to invalidate registers. This will come with better analysis
722 * (liveness analysis) of the incoming program.
724 emit_pshufd(cp
, dst
, arg0
, SHUF(Y
, Z
, X
, W
));
725 emit_pshufd(cp
, tmp1
, arg1
, SHUF(Z
, X
, Y
, W
));
726 sse_mulps(&cp
->func
, dst
, tmp1
);
727 emit_pshufd(cp
, tmp0
, arg0
, SHUF(Z
, X
, Y
, W
));
728 emit_pshufd(cp
, tmp1
, arg1
, SHUF(Y
, Z
, X
, W
));
729 sse_mulps(&cp
->func
, tmp0
, tmp1
);
730 sse_subps(&cp
->func
, dst
, tmp0
);
732 /* dst[0] = arg0[1] * arg1[2] - arg0[2] * arg1[1]; */
733 /* dst[1] = arg0[2] * arg1[0] - arg0[0] * arg1[2]; */
734 /* dst[2] = arg0[0] * arg1[1] - arg0[1] * arg1[0]; */
735 /* dst[3] is undef */
740 static GLboolean
emit_NOP( struct compilation
*cp
, union instruction op
)
746 static GLboolean (* const emit_func
[])(struct compilation
*, union instruction
) =
783 static GLint
get_offset( const void *a
, const void *b
)
785 return (const char *)b
- (const char *)a
;
789 static GLboolean
build_vertex_program( struct compilation
*cp
)
793 struct x86_reg regEAX
= x86_make_reg(file_REG32
, reg_AX
);
794 struct x86_reg parmECX
= x86_make_reg(file_REG32
, reg_CX
);
796 x86_mov(&cp
->func
, regEAX
, x86_fn_arg(&cp
->func
, 1));
797 x86_mov(&cp
->func
, parmECX
, regEAX
);
799 x86_mov(&cp
->func
, regEAX
, x86_make_disp(regEAX
, get_offset(cp
->m
, cp
->m
->File
+ FILE_REG
)));
800 x86_mov(&cp
->func
, parmECX
, x86_make_disp(parmECX
, get_offset(cp
->m
, cp
->m
->File
+ FILE_STATE_PARAM
)));
802 for (j
= 0; j
< cp
->m
->nr_instructions
; j
++) {
803 union instruction inst
= cp
->m
->instructions
[j
];
804 cp
->insn_counter
= j
+1; /* avoid zero */
807 _mesa_printf("%p: ", cp
->func
.csr
);
808 _tnl_disassem_vba_insn( inst
);
812 if (!emit_func
[inst
.alu
.opcode
]( cp
, inst
)) {
817 /* TODO: only for outputs:
819 for (j
= 0; j
< 8; j
++) {
820 if (cp
->xmm
[j
].dirty
)
827 if (cp
->func
.need_emms
)
836 * Execute the given vertex program.
838 * TODO: Integrate the t_vertex.c code here, to build machine vertices
839 * directly at this point.
841 * TODO: Eliminate the VB struct entirely and just use
842 * struct arb_vertex_machine.
845 _tnl_sse_codegen_vertex_program(struct arb_vp_machine
*m
)
847 struct compilation cp
;
849 memset(&cp
, 0, sizeof(cp
));
854 free((void *)m
->func
);
858 x86_init_func(&cp
.func
);
860 if (!build_vertex_program(&cp
)) {
861 x86_release_func( &cp
.func
);
865 m
->func
= (void (*)(struct arb_vp_machine
*))x86_get_func( &cp
.func
);
874 _tnl_sse_codegen_vertex_program( GLcontext
*ctx
)
876 /* Dummy version for when USE_SSE_ASM not defined */