aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/extras/Mesa/src/mesa/tnl/t_vb_arbprogram_sse.c
diff options
context:
space:
mode:
Diffstat (limited to 'nx-X11/extras/Mesa/src/mesa/tnl/t_vb_arbprogram_sse.c')
-rw-r--r--nx-X11/extras/Mesa/src/mesa/tnl/t_vb_arbprogram_sse.c1222
1 files changed, 0 insertions, 1222 deletions
diff --git a/nx-X11/extras/Mesa/src/mesa/tnl/t_vb_arbprogram_sse.c b/nx-X11/extras/Mesa/src/mesa/tnl/t_vb_arbprogram_sse.c
deleted file mode 100644
index 330d30efb..000000000
--- a/nx-X11/extras/Mesa/src/mesa/tnl/t_vb_arbprogram_sse.c
+++ /dev/null
@@ -1,1222 +0,0 @@
-/*
- * Mesa 3-D graphics library
- * Version: 6.3
- *
- * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file t_vb_arb_program_sse.c
- *
- * Translate simplified vertex_program representation to
- * x86/x87/SSE/SSE2 machine code using mesa's rtasm runtime assembler.
- *
- * This is very much a first attempt - build something that works.
- * There are probably better approaches for applying SSE to vertex
- * programs, and the whole thing is crying out for static analysis of
- * the programs to avoid redundant operations.
- *
- * \author Keith Whitwell
- */
-
-#include "glheader.h"
-#include "context.h"
-#include "imports.h"
-#include "macros.h"
-#include "mtypes.h"
-#include "arbprogparse.h"
-#include "program.h"
-#include "math/m_matrix.h"
-#include "math/m_translate.h"
-#include "t_context.h"
-#include "t_vb_arbprogram.h"
-
-#if defined(USE_SSE_ASM)
-
-#include "x86/rtasm/x86sse.h"
-#include "x86/common_x86_asm.h"
-
-#define X 0
-#define Y 1
-#define Z 2
-#define W 3
-
-/* Reg usage:
- *
- * EAX - temp
- * EBX - point to 'm->File[0]'
- * ECX - point to 'm->File[3]'
- * EDX - holds 'm'
- * EBP,
- * ESI,
- * EDI
- */
-
-#define DISASSEM 0
-
-#define FAIL \
-do { \
- _mesa_printf("x86 translation failed in %s\n", __FUNCTION__); \
- return GL_FALSE; \
-} while (0)
-
-struct compilation {
- struct x86_function func;
- struct tnl_compiled_program *p;
- GLuint insn_counter;
-
- struct {
- GLuint file:2;
- GLuint idx:7;
- GLuint dirty:1;
- GLuint last_used:10;
- } xmm[8];
-
- struct {
- struct x86_reg base;
- } file[4];
-
- GLboolean have_sse2;
- GLshort fpucntl;
-};
-
-static INLINE GLboolean eq( struct x86_reg a,
- struct x86_reg b )
-{
- return (a.file == b.file &&
- a.idx == b.idx &&
- a.mod == b.mod &&
- a.disp == b.disp);
-}
-
-static GLint get_offset( const void *a, const void *b )
-{
- return (const char *)b - (const char *)a;
-}
-
-
-static struct x86_reg get_reg_ptr(GLuint file,
- GLuint idx )
-{
- struct x86_reg reg;
-
- switch (file) {
- case FILE_REG:
- reg = x86_make_reg(file_REG32, reg_BX);
- assert(idx != REG_UNDEF);
- break;
- case FILE_STATE_PARAM:
- reg = x86_make_reg(file_REG32, reg_CX);
- break;
- default:
- assert(0);
- }
-
- return x86_make_disp(reg, 16 * idx);
-}
-
-
-static void spill( struct compilation *cp, GLuint idx )
-{
- struct x86_reg oldval = get_reg_ptr(cp->xmm[idx].file,
- cp->xmm[idx].idx);
-
- assert(cp->xmm[idx].dirty);
- sse_movups(&cp->func, oldval, x86_make_reg(file_XMM, idx));
- cp->xmm[idx].dirty = 0;
-}
-
-static struct x86_reg get_xmm_reg( struct compilation *cp )
-{
- GLuint i;
- GLuint oldest = 0;
-
- for (i = 0; i < 8; i++)
- if (cp->xmm[i].last_used < cp->xmm[oldest].last_used)
- oldest = i;
-
- /* Need to write out the old value?
- */
- if (cp->xmm[oldest].dirty)
- spill(cp, oldest);
-
- assert(cp->xmm[oldest].last_used != cp->insn_counter);
-
- cp->xmm[oldest].file = FILE_REG;
- cp->xmm[oldest].idx = REG_UNDEF;
- cp->xmm[oldest].last_used = cp->insn_counter;
- return x86_make_reg(file_XMM, oldest);
-}
-
-static void invalidate_xmm( struct compilation *cp,
- GLuint file, GLuint idx )
-{
- GLuint i;
-
- /* Invalidate any old copy of this register in XMM0-7.
- */
- for (i = 0; i < 8; i++) {
- if (cp->xmm[i].file == file && cp->xmm[i].idx == idx) {
- cp->xmm[i].file = FILE_REG;
- cp->xmm[i].idx = REG_UNDEF;
- cp->xmm[i].dirty = 0;
- break;
- }
- }
-}
-
-
-/* Return an XMM reg to receive the results of an operation.
- */
-static struct x86_reg get_dst_xmm_reg( struct compilation *cp,
- GLuint file, GLuint idx )
-{
- struct x86_reg reg;
-
- /* Invalidate any old copy of this register in XMM0-7. Don't reuse
- * as this may be one of the arguments.
- */
- invalidate_xmm( cp, file, idx );
-
- reg = get_xmm_reg( cp );
- cp->xmm[reg.idx].file = file;
- cp->xmm[reg.idx].idx = idx;
- cp->xmm[reg.idx].dirty = 1;
- return reg;
-}
-
-/* As above, but return a pointer. Note - this pointer may alias
- * those returned by get_arg_ptr().
- */
-static struct x86_reg get_dst_ptr( struct compilation *cp,
- GLuint file, GLuint idx )
-{
- /* Invalidate any old copy of this register in XMM0-7. Don't reuse
- * as this may be one of the arguments.
- */
- invalidate_xmm( cp, file, idx );
-
- return get_reg_ptr(file, idx);
-}
-
-
-
-/* Return an XMM reg if the argument is resident, otherwise return a
- * base+offset pointer to the saved value.
- */
-static struct x86_reg get_arg( struct compilation *cp, GLuint file, GLuint idx )
-{
- GLuint i;
-
- for (i = 0; i < 8; i++) {
- if (cp->xmm[i].file == file &&
- cp->xmm[i].idx == idx) {
- cp->xmm[i].last_used = cp->insn_counter;
- return x86_make_reg(file_XMM, i);
- }
- }
-
- return get_reg_ptr(file, idx);
-}
-
-/* As above, but always return a pointer:
- */
-static struct x86_reg get_arg_ptr( struct compilation *cp, GLuint file, GLuint idx )
-{
- GLuint i;
-
- /* If there is a modified version of this register in one of the
- * XMM regs, write it out to memory.
- */
- for (i = 0; i < 8; i++) {
- if (cp->xmm[i].file == file &&
- cp->xmm[i].idx == idx &&
- cp->xmm[i].dirty)
- spill(cp, i);
- }
-
- return get_reg_ptr(file, idx);
-}
-
-/* Emulate pshufd insn in regular SSE, if necessary:
- */
-static void emit_pshufd( struct compilation *cp,
- struct x86_reg dst,
- struct x86_reg arg0,
- GLubyte shuf )
-{
- if (cp->have_sse2) {
- sse2_pshufd(&cp->func, dst, arg0, shuf);
- cp->func.fn = 0;
- }
- else {
- if (!eq(dst, arg0))
- sse_movups(&cp->func, dst, arg0);
-
- sse_shufps(&cp->func, dst, dst, shuf);
- }
-}
-
-static void set_fpu_round_neg_inf( struct compilation *cp )
-{
- if (cp->fpucntl != RND_NEG_FPU) {
- struct x86_reg regEDX = x86_make_reg(file_REG32, reg_DX);
- struct arb_vp_machine *m = NULL;
-
- cp->fpucntl = RND_NEG_FPU;
- x87_fnclex(&cp->func);
- x87_fldcw(&cp->func, x86_make_disp(regEDX, get_offset(m, &m->fpucntl_rnd_neg)));
- }
-}
-
-
-/* Perform a reduced swizzle.
- */
-static GLboolean emit_RSW( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.rsw.file0, op.rsw.idx0);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.rsw.dst);
- GLuint swz = op.rsw.swz;
- GLuint neg = op.rsw.neg;
-
- emit_pshufd(cp, dst, arg0, swz);
-
- if (neg) {
- struct x86_reg negs = get_arg(cp, FILE_REG, REG_SWZ);
- struct x86_reg tmp = get_xmm_reg(cp);
- /* Load 1,-1,0,0
- * Use neg as arg to pshufd
- * Multiply
- */
- emit_pshufd(cp, tmp, negs,
- SHUF((neg & 1) ? 1 : 0,
- (neg & 2) ? 1 : 0,
- (neg & 4) ? 1 : 0,
- (neg & 8) ? 1 : 0));
- sse_mulps(&cp->func, dst, tmp);
- }
-
- return GL_TRUE;
-}
-
-/* Helper for writemask:
- */
-static GLboolean emit_shuf_copy1( struct compilation *cp,
- struct x86_reg dst,
- struct x86_reg arg0,
- struct x86_reg arg1,
- GLubyte shuf )
-{
- struct x86_reg tmp = get_xmm_reg(cp);
- sse_movups(&cp->func, dst, arg1);
- emit_pshufd(cp, dst, dst, shuf);
- emit_pshufd(cp, tmp, arg0, shuf);
-
- sse_movss(&cp->func, dst, tmp);
-
- emit_pshufd(cp, dst, dst, shuf);
- return GL_TRUE;
-}
-
-
-/* Helper for writemask:
- */
-static GLboolean emit_shuf_copy2( struct compilation *cp,
- struct x86_reg dst,
- struct x86_reg arg0,
- struct x86_reg arg1,
- GLubyte shuf )
-{
- struct x86_reg tmp = get_xmm_reg(cp);
- emit_pshufd(cp, dst, arg1, shuf);
- emit_pshufd(cp, tmp, arg0, shuf);
-
- sse_shufps(&cp->func, dst, tmp, SHUF(X, Y, Z, W));
-
- emit_pshufd(cp, dst, dst, shuf);
- return GL_TRUE;
-}
-
-
-static void emit_x87_ex2( struct compilation *cp )
-{
- struct x86_reg st0 = x86_make_reg(file_x87, 0);
- struct x86_reg st1 = x86_make_reg(file_x87, 1);
- struct x86_reg st3 = x86_make_reg(file_x87, 3);
-
- set_fpu_round_neg_inf( cp );
-
- x87_fld(&cp->func, st0); /* a a */
- x87_fprndint( &cp->func ); /* int(a) a */
- x87_fld(&cp->func, st0); /* int(a) int(a) a */
- x87_fstp(&cp->func, st3); /* int(a) a int(a)*/
- x87_fsubp(&cp->func, st1); /* frac(a) int(a) */
- x87_f2xm1(&cp->func); /* (2^frac(a))-1 int(a)*/
- x87_fld1(&cp->func); /* 1 (2^frac(a))-1 int(a)*/
- x87_faddp(&cp->func, st1); /* 2^frac(a) int(a) */
- x87_fscale(&cp->func); /* 2^a */
-}
-
-#if 0
-static GLboolean emit_MSK2( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.msk.file, op.msk.arg);
- struct x86_reg arg1 = get_arg(cp, FILE_REG, op.msk.dst); /* NOTE! */
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.msk.dst);
-
- /* make full width bitmask in tmp
- * dst = ~tmp
- * tmp &= arg0
- * dst &= arg1
- * dst |= tmp
- */
- emit_pshufd(cp, tmp, get_arg(cp, FILE_REG, REG_NEGS),
- SHUF((op.msk.mask & 1) ? 2 : 0,
- (op.msk.mask & 2) ? 2 : 0,
- (op.msk.mask & 4) ? 2 : 0,
- (op.msk.mask & 8) ? 2 : 0));
- sse2_pnot(&cp->func, dst, tmp);
- sse2_pand(&cp->func, arg0, tmp);
- sse2_pand(&cp->func, arg1, dst);
- sse2_por(&cp->func, tmp, dst);
- return GL_TRUE;
-}
-#endif
-
-
-/* Used to implement write masking. This and most of the other instructions
- * here would be easier to implement if there had been a translation
- * to a 2 argument format (dst/arg0, arg1) at the shader level before
- * attempting to translate to x86/sse code.
- */
-static GLboolean emit_MSK( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg = get_arg(cp, op.msk.file, op.msk.idx);
- struct x86_reg dst0 = get_arg(cp, FILE_REG, op.msk.dst); /* NOTE! */
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.msk.dst);
-
- /* Note that dst and dst0 refer to the same program variable, but
- * will definitely be different XMM registers. We're effectively
- * treating this as a 2 argument SEL now, just one of which happens
- * always to be the same register as the destination.
- */
-
- switch (op.msk.mask) {
- case 0:
- sse_movups(&cp->func, dst, dst0);
- return GL_TRUE;
-
- case WRITEMASK_X:
- if (arg.file == file_XMM) {
- sse_movups(&cp->func, dst, dst0);
- sse_movss(&cp->func, dst, arg);
- }
- else {
- struct x86_reg tmp = get_xmm_reg(cp);
- sse_movups(&cp->func, dst, dst0);
- sse_movss(&cp->func, tmp, arg);
- sse_movss(&cp->func, dst, tmp);
- }
- return GL_TRUE;
-
- case WRITEMASK_XY:
- sse_movups(&cp->func, dst, dst0);
- sse_shufps(&cp->func, dst, arg, SHUF(X, Y, Z, W));
- return GL_TRUE;
-
- case WRITEMASK_ZW:
- sse_movups(&cp->func, dst, arg);
- sse_shufps(&cp->func, dst, dst0, SHUF(X, Y, Z, W));
- return GL_TRUE;
-
- case WRITEMASK_YZW:
- if (dst0.file == file_XMM) {
- sse_movups(&cp->func, dst, arg);
- sse_movss(&cp->func, dst, dst0);
- }
- else {
- struct x86_reg tmp = get_xmm_reg(cp);
- sse_movups(&cp->func, dst, arg);
- sse_movss(&cp->func, tmp, dst0);
- sse_movss(&cp->func, dst, tmp);
- }
- return GL_TRUE;
-
- case WRITEMASK_Y:
- emit_shuf_copy1(cp, dst, arg, dst0, SHUF(Y,X,Z,W));
- return GL_TRUE;
-
- case WRITEMASK_Z:
- emit_shuf_copy1(cp, dst, arg, dst0, SHUF(Z,Y,X,W));
- return GL_TRUE;
-
- case WRITEMASK_W:
- emit_shuf_copy1(cp, dst, arg, dst0, SHUF(W,Y,Z,X));
- return GL_TRUE;
-
- case WRITEMASK_XZ:
- emit_shuf_copy2(cp, dst, arg, dst0, SHUF(X,Z,Y,W));
- return GL_TRUE;
-
- case WRITEMASK_XW:
- emit_shuf_copy2(cp, dst, arg, dst0, SHUF(X,W,Z,Y));
-
- case WRITEMASK_YZ:
- emit_shuf_copy2(cp, dst, arg, dst0, SHUF(Z,Y,X,W));
- return GL_TRUE;
-
- case WRITEMASK_YW:
- emit_shuf_copy2(cp, dst, arg, dst0, SHUF(W,Y,Z,X));
- return GL_TRUE;
-
- case WRITEMASK_XZW:
- emit_shuf_copy1(cp, dst, dst0, arg, SHUF(Y,X,Z,W));
- return GL_TRUE;
-
- case WRITEMASK_XYW:
- emit_shuf_copy1(cp, dst, dst0, arg, SHUF(Z,Y,X,W));
- return GL_TRUE;
-
- case WRITEMASK_XYZ:
- emit_shuf_copy1(cp, dst, dst0, arg, SHUF(W,Y,Z,X));
- return GL_TRUE;
-
- case WRITEMASK_XYZW:
- sse_movups(&cp->func, dst, arg);
- return GL_TRUE;
-
- default:
- assert(0);
- break;
- }
-}
-
-
-
-static GLboolean emit_PRT( struct compilation *cp, union instruction op )
-{
- FAIL;
-}
-
-
-/**
- * The traditional instructions. All operate on internal registers
- * and ignore write masks and swizzling issues.
- */
-
-static GLboolean emit_ABS( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg neg = get_reg_ptr(FILE_REG, REG_NEG);
-
- sse_movups(&cp->func, dst, arg0);
- sse_mulps(&cp->func, dst, neg);
- sse_maxps(&cp->func, dst, arg0);
- return GL_TRUE;
-}
-
-static GLboolean emit_ADD( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
-
- sse_movups(&cp->func, dst, arg0);
- sse_addps(&cp->func, dst, arg1);
- return GL_TRUE;
-}
-
-
-/* The dotproduct instructions don't really do that well in sse:
- */
-static GLboolean emit_DP3( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg tmp = get_xmm_reg(cp);
-
- sse_movups(&cp->func, dst, arg0);
- sse_mulps(&cp->func, dst, arg1);
-
- /* Now the hard bit: sum the first 3 values:
- */
- sse_movhlps(&cp->func, tmp, dst);
- sse_addss(&cp->func, dst, tmp); /* a*x+c*z, b*y, ?, ? */
- emit_pshufd(cp, tmp, dst, SHUF(Y,X,W,Z));
- sse_addss(&cp->func, dst, tmp);
- sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X));
- return GL_TRUE;
-}
-
-
-
-static GLboolean emit_DP4( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg tmp = get_xmm_reg(cp);
-
- sse_movups(&cp->func, dst, arg0);
- sse_mulps(&cp->func, dst, arg1);
-
- /* Now the hard bit: sum the values:
- */
- sse_movhlps(&cp->func, tmp, dst);
- sse_addps(&cp->func, dst, tmp); /* a*x+c*z, b*y+d*w, a*x+c*z, b*y+d*w */
- emit_pshufd(cp, tmp, dst, SHUF(Y,X,W,Z));
- sse_addss(&cp->func, dst, tmp);
- sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X));
- return GL_TRUE;
-}
-
-static GLboolean emit_DPH( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg ones = get_reg_ptr(FILE_REG, REG_ONES);
- struct x86_reg tmp = get_xmm_reg(cp);
-
- emit_pshufd(cp, dst, arg0, SHUF(W,X,Y,Z));
- sse_movss(&cp->func, dst, ones);
- emit_pshufd(cp, dst, dst, SHUF(W,X,Y,Z));
- sse_mulps(&cp->func, dst, arg1);
-
- /* Now the hard bit: sum the values (from DP4):
- */
- sse_movhlps(&cp->func, tmp, dst);
- sse_addps(&cp->func, dst, tmp); /* a*x+c*z, b*y+d*w, a*x+c*z, b*y+d*w */
- emit_pshufd(cp, tmp, dst, SHUF(Y,X,W,Z));
- sse_addss(&cp->func, dst, tmp);
- sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X));
- return GL_TRUE;
-}
-
-#if 0
-static GLboolean emit_DST( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg_ptr(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
-
-/* dst[0] = 1.0 * 1.0F; */
-/* dst[1] = arg0[1] * arg1[1]; */
-/* dst[2] = arg0[2] * 1.0; */
-/* dst[3] = 1.0 * arg1[3]; */
-
- /* Would rather do some of this with integer regs, but:
- * 1) No proper support for immediate values yet
- * 2) I'd need to push/pop somewhere to get a free reg.
- */
- x87_fld1(&cp->func);
- x87_fstp(&cp->func, dst); /* would rather do an immediate store... */
- x87_fld(&cp->func, x86_make_disp(arg0, 4));
- x87_fmul(&cp->func, x86_make_disp(arg1, 4));
- x87_fstp(&cp->func, x86_make_disp(dst, 4));
-
- if (!eq(arg0, dst)) {
- x86_fld(&cp->func, x86_make_disp(arg0, 8));
- x86_stp(&cp->func, x86_make_disp(dst, 8));
- }
-
- if (!eq(arg1, dst)) {
- x86_fld(&cp->func, x86_make_disp(arg0, 12));
- x86_stp(&cp->func, x86_make_disp(dst, 12));
- }
-
- return GL_TRUE;
-}
-#else
-static GLboolean emit_DST( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg tmp = get_xmm_reg(cp);
- struct x86_reg ones = get_reg_ptr(FILE_REG, REG_ONES);
-
- emit_shuf_copy2(cp, dst, arg0, ones, SHUF(X,W,Z,Y));
- emit_shuf_copy2(cp, tmp, arg1, ones, SHUF(X,Z,Y,W));
- sse_mulps(&cp->func, dst, tmp);
-
-/* dst[0] = 1.0 * 1.0F; */
-/* dst[1] = arg0[1] * arg1[1]; */
-/* dst[2] = arg0[2] * 1.0; */
-/* dst[3] = 1.0 * arg1[3]; */
-
- return GL_TRUE;
-}
-#endif
-
-static GLboolean emit_LG2( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
-
- x87_fld1(&cp->func); /* 1 */
- x87_fld(&cp->func, arg0); /* a0 1 */
- x87_fyl2x(&cp->func); /* log2(a0) */
- x87_fst(&cp->func, x86_make_disp(dst, 0));
- x87_fst(&cp->func, x86_make_disp(dst, 4));
- x87_fst(&cp->func, x86_make_disp(dst, 8));
- x87_fstp(&cp->func, x86_make_disp(dst, 12));
-
- return GL_TRUE;
-}
-
-
-static GLboolean emit_EX2( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
-
- /* CAUTION: dst may alias arg0!
- */
- x87_fld(&cp->func, arg0);
-
- emit_x87_ex2(cp);
-
- x87_fst(&cp->func, x86_make_disp(dst, 0));
- x87_fst(&cp->func, x86_make_disp(dst, 4));
- x87_fst(&cp->func, x86_make_disp(dst, 8));
- x87_fst(&cp->func, x86_make_disp(dst, 12));
- return GL_TRUE;
-}
-
-static GLboolean emit_EXP( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
- struct x86_reg st0 = x86_make_reg(file_x87, 0);
- struct x86_reg st1 = x86_make_reg(file_x87, 1);
- struct x86_reg st3 = x86_make_reg(file_x87, 3);
-
- /* CAUTION: dst may alias arg0!
- */
- x87_fld(&cp->func, arg0); /* arg0.x */
- x87_fld(&cp->func, st0); /* arg arg */
-
- /* by default, fpu is setup to round-to-nearest. We want to
- * change this now, and track the state through to the end of the
- * generated function so that it isn't repeated unnecessarily.
- * Alternately, could subtract .5 to get round to -inf behaviour.
- */
- set_fpu_round_neg_inf( cp );
- x87_fprndint( &cp->func ); /* flr(a) a */
- x87_fld(&cp->func, st0); /* flr(a) flr(a) a */
- x87_fld1(&cp->func); /* 1 floor(a) floor(a) a */
- x87_fst(&cp->func, x86_make_disp(dst, 12)); /* stack unchanged */
- x87_fscale(&cp->func); /* 2^floor(a) floor(a) a */
- x87_fst(&cp->func, st3); /* 2^floor(a) floor(a) a 2^floor(a)*/
- x87_fstp(&cp->func, x86_make_disp(dst, 0)); /* flr(a) a 2^flr(a) */
- x87_fsubrp(&cp->func, st1); /* frac(a) 2^flr(a) */
- x87_fst(&cp->func, x86_make_disp(dst, 4)); /* frac(a) 2^flr(a) */
- x87_f2xm1(&cp->func); /* (2^frac(a))-1 2^flr(a)*/
- x87_fld1(&cp->func); /* 1 (2^frac(a))-1 2^flr(a)*/
- x87_faddp(&cp->func, st1); /* 2^frac(a) 2^flr(a) */
- x87_fmulp(&cp->func, st1); /* 2^a */
- x87_fst(&cp->func, x86_make_disp(dst, 8));
-
-
-
-/* dst[0] = 2^floor(tmp); */
-/* dst[1] = frac(tmp); */
-/* dst[2] = 2^floor(tmp) * 2^frac(tmp); */
-/* dst[3] = 1.0F; */
- return GL_TRUE;
-}
-
-static GLboolean emit_LOG( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
- struct x86_reg st0 = x86_make_reg(file_x87, 0);
- struct x86_reg st1 = x86_make_reg(file_x87, 1);
- struct x86_reg st2 = x86_make_reg(file_x87, 2);
-
- /* CAUTION: dst may alias arg0!
- */
- x87_fld(&cp->func, arg0); /* arg0.x */
- x87_fabs(&cp->func); /* |arg0.x| */
- x87_fxtract(&cp->func); /* mantissa(arg0.x), exponent(arg0.x) */
- x87_fst(&cp->func, st2); /* mantissa, exponent, mantissa */
- x87_fld1(&cp->func); /* 1, mantissa, exponent, mantissa */
- x87_fyl2x(&cp->func); /* log2(mantissa), exponent, mantissa */
- x87_fadd(&cp->func, st0, st1); /* e+l2(m), e, m */
- x87_fstp(&cp->func, x86_make_disp(dst, 8)); /* e, m */
-
- x87_fld1(&cp->func); /* 1, e, m */
- x87_fsub(&cp->func, st1, st0); /* 1, e-1, m */
- x87_fstp(&cp->func, x86_make_disp(dst, 12)); /* e-1,m */
- x87_fstp(&cp->func, dst); /* m */
-
- x87_fadd(&cp->func, st0, st0); /* 2m */
- x87_fstp(&cp->func, x86_make_disp(dst, 4));
-
- return GL_TRUE;
-}
-
-static GLboolean emit_FLR( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
- int i;
-
- set_fpu_round_neg_inf( cp );
-
- for (i = 0; i < 4; i++) {
- x87_fld(&cp->func, x86_make_disp(arg0, i*4));
- x87_fprndint( &cp->func );
- x87_fstp(&cp->func, x86_make_disp(dst, i*4));
- }
-
-
- return GL_TRUE;
-}
-
-static GLboolean emit_FRC( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
- struct x86_reg st0 = x86_make_reg(file_x87, 0);
- struct x86_reg st1 = x86_make_reg(file_x87, 1);
- int i;
-
- set_fpu_round_neg_inf( cp );
-
- /* Knowing liveness info or even just writemask would be useful
- * here:
- */
- for (i = 0; i < 4; i++) {
- x87_fld(&cp->func, x86_make_disp(arg0, i*4));
- x87_fld(&cp->func, st0); /* a a */
- x87_fprndint( &cp->func ); /* flr(a) a */
- x87_fsubrp(&cp->func, st1); /* frc(a) */
- x87_fstp(&cp->func, x86_make_disp(dst, i*4));
- }
-
- return GL_TRUE;
-}
-
-
-
-static GLboolean emit_LIT( struct compilation *cp, union instruction op )
-{
-#if 1
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
- struct x86_reg lit = get_arg(cp, FILE_REG, REG_LIT);
- struct x86_reg tmp = get_xmm_reg(cp);
- struct x86_reg st1 = x86_make_reg(file_x87, 1);
- struct x86_reg regEAX = x86_make_reg(file_REG32, reg_AX);
- GLubyte *fixup1, *fixup2;
-
-
- /* Load the interesting parts of arg0:
- */
- x87_fld(&cp->func, x86_make_disp(arg0, 12)); /* a3 */
- x87_fld(&cp->func, x86_make_disp(arg0, 4)); /* a1 a3 */
- x87_fld(&cp->func, x86_make_disp(arg0, 0)); /* a0 a1 a3 */
-
- /* Intialize dst:
- */
- sse_movaps(&cp->func, tmp, lit);
- sse_movaps(&cp->func, dst, tmp);
-
- /* Check arg0[0]:
- */
- x87_fldz(&cp->func); /* 0 a0 a1 a3 */
- x87_fucomp(&cp->func, st1); /* a0 a1 a3 */
- x87_fnstsw(&cp->func, regEAX);
- x86_sahf(&cp->func);
- fixup1 = x86_jcc_forward(&cp->func, cc_AE);
-
- x87_fstp(&cp->func, x86_make_disp(dst, 4)); /* a1 a3 */
-
- /* Check arg0[1]:
- */
- x87_fldz(&cp->func); /* 0 a1 a3 */
- x87_fucomp(&cp->func, st1); /* a1 a3 */
- x87_fnstsw(&cp->func, regEAX);
- x86_sahf(&cp->func);
- fixup2 = x86_jcc_forward(&cp->func, cc_AE);
-
- /* Compute pow(a1, a3)
- */
- x87_fyl2x(&cp->func); /* a3*log2(a1) */
-
- emit_x87_ex2( cp ); /* 2^(a3*log2(a1)) */
-
- x87_fstp(&cp->func, x86_make_disp(dst, 8));
-
- /* Land jumps:
- */
- x86_fixup_fwd_jump(&cp->func, fixup1);
- x86_fixup_fwd_jump(&cp->func, fixup2);
-#else
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg ones = get_reg_ptr(FILE_REG, REG_LIT);
- sse_movups(&cp->func, dst, ones);
-#endif
- return GL_TRUE;
-}
-
-
-
-static GLboolean emit_MAX( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
-
- sse_movups(&cp->func, dst, arg0);
- sse_maxps(&cp->func, dst, arg1);
- return GL_TRUE;
-}
-
-
-static GLboolean emit_MIN( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
-
- sse_movups(&cp->func, dst, arg0);
- sse_minps(&cp->func, dst, arg1);
- return GL_TRUE;
-}
-
-static GLboolean emit_MOV( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
-
- sse_movups(&cp->func, dst, arg0);
- return GL_TRUE;
-}
-
-static GLboolean emit_MUL( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
-
- sse_movups(&cp->func, dst, arg0);
- sse_mulps(&cp->func, dst, arg1);
- return GL_TRUE;
-}
-
-
-static GLboolean emit_POW( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg_ptr(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
-
- x87_fld(&cp->func, arg1); /* a1 */
- x87_fld(&cp->func, arg0); /* a0 a1 */
- x87_fyl2x(&cp->func); /* a1*log2(a0) */
-
- emit_x87_ex2( cp ); /* 2^(a1*log2(a0)) */
-
- x87_fst(&cp->func, x86_make_disp(dst, 0));
- x87_fst(&cp->func, x86_make_disp(dst, 4));
- x87_fst(&cp->func, x86_make_disp(dst, 8));
- x87_fstp(&cp->func, x86_make_disp(dst, 12));
-
- return GL_TRUE;
-}
-
-static GLboolean emit_REL( struct compilation *cp, union instruction op )
-{
-/* GLuint idx = (op.alu.idx0 + (GLint)cp->File[0][REG_ADDR][0]) & (MAX_NV_VERTEX_PROGRAM_PARAMS-1); */
-/* GLuint idx = 0; */
-/* struct x86_reg arg0 = get_arg(cp, op.alu.file0, idx); */
-/* struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst); */
-
-/* dst[0] = arg0[0]; */
-/* dst[1] = arg0[1]; */
-/* dst[2] = arg0[2]; */
-/* dst[3] = arg0[3]; */
-
- FAIL;
-}
-
-static GLboolean emit_RCP( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
-
- if (cp->have_sse2) {
- sse2_rcpss(&cp->func, dst, arg0);
- }
- else {
- struct x86_reg ones = get_reg_ptr(FILE_REG, REG_ONES);
- sse_movss(&cp->func, dst, ones);
- sse_divss(&cp->func, dst, arg0);
- }
-
- sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X));
- return GL_TRUE;
-}
-
-static GLboolean emit_RSQ( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
-
- /* TODO: Calculate absolute value
- */
-#if 0
- sse_movss(&cp->func, dst, arg0);
- sse_mulss(&cp->func, dst, neg);
- sse_maxss(&cp->func, dst, arg0);
-#endif
-
- sse_rsqrtss(&cp->func, dst, arg0);
- sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X));
- return GL_TRUE;
-}
-
-
-static GLboolean emit_SGE( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg ones = get_reg_ptr(FILE_REG, REG_ONES);
-
- sse_movups(&cp->func, dst, arg0);
- sse_cmpps(&cp->func, dst, arg1, cc_NotLessThan);
- sse_andps(&cp->func, dst, ones);
- return GL_TRUE;
-}
-
-
-static GLboolean emit_SLT( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg ones = get_reg_ptr(FILE_REG, REG_ONES);
-
- sse_movups(&cp->func, dst, arg0);
- sse_cmpps(&cp->func, dst, arg1, cc_LessThan);
- sse_andps(&cp->func, dst, ones);
- return GL_TRUE;
-}
-
-static GLboolean emit_SUB( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
-
- sse_movups(&cp->func, dst, arg0);
- sse_subps(&cp->func, dst, arg1);
- return GL_TRUE;
-}
-
-
-static GLboolean emit_XPD( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg tmp0 = get_xmm_reg(cp);
- struct x86_reg tmp1 = get_xmm_reg(cp);
-
- /* Could avoid tmp0, tmp1 if we overwrote arg0, arg1. Need a way
- * to invalidate registers. This will come with better analysis
- * (liveness analysis) of the incoming program.
- */
- emit_pshufd(cp, dst, arg0, SHUF(Y, Z, X, W));
- emit_pshufd(cp, tmp1, arg1, SHUF(Z, X, Y, W));
- sse_mulps(&cp->func, dst, tmp1);
- emit_pshufd(cp, tmp0, arg0, SHUF(Z, X, Y, W));
- emit_pshufd(cp, tmp1, arg1, SHUF(Y, Z, X, W));
- sse_mulps(&cp->func, tmp0, tmp1);
- sse_subps(&cp->func, dst, tmp0);
-
-/* dst[0] = arg0[1] * arg1[2] - arg0[2] * arg1[1]; */
-/* dst[1] = arg0[2] * arg1[0] - arg0[0] * arg1[2]; */
-/* dst[2] = arg0[0] * arg1[1] - arg0[1] * arg1[0]; */
-/* dst[3] is undef */
-
- return GL_TRUE;
-}
-
-static GLboolean emit_NOP( struct compilation *cp, union instruction op )
-{
- return GL_TRUE;
-}
-
-
-static GLboolean (* const emit_func[])(struct compilation *, union instruction) =
-{
- emit_ABS,
- emit_ADD,
- emit_NOP,
- emit_DP3,
- emit_DP4,
- emit_DPH,
- emit_DST,
- emit_NOP,
- emit_EX2,
- emit_EXP,
- emit_FLR,
- emit_FRC,
- emit_LG2,
- emit_LIT,
- emit_LOG,
- emit_NOP,
- emit_MAX,
- emit_MIN,
- emit_MOV,
- emit_MUL,
- emit_POW,
- emit_PRT,
- emit_NOP,
- emit_RCP,
- emit_RSQ,
- emit_SGE,
- emit_SLT,
- emit_SUB,
- emit_RSW,
- emit_XPD,
- emit_RSW,
- emit_MSK,
- emit_REL,
-};
-
-
-
-static GLboolean build_vertex_program( struct compilation *cp )
-{
- struct arb_vp_machine *m = NULL;
- GLuint j;
-
- struct x86_reg regEBX = x86_make_reg(file_REG32, reg_BX);
- struct x86_reg regECX = x86_make_reg(file_REG32, reg_CX);
- struct x86_reg regEDX = x86_make_reg(file_REG32, reg_DX);
-
- x86_push(&cp->func, regEBX);
-
- x86_mov(&cp->func, regEDX, x86_fn_arg(&cp->func, 1));
- x86_mov(&cp->func, regEBX, x86_make_disp(regEDX, get_offset(m, m->File + FILE_REG)));
- x86_mov(&cp->func, regECX, x86_make_disp(regEDX, get_offset(m, m->File + FILE_STATE_PARAM)));
-
- for (j = 0; j < cp->p->nr_instructions; j++) {
- union instruction inst = cp->p->instructions[j];
- cp->insn_counter = j+1; /* avoid zero */
-
- if (DISASSEM) {
- _mesa_printf("%p: ", cp->func.csr);
- _tnl_disassem_vba_insn( inst );
- }
- cp->func.fn = NULL;
-
- if (!emit_func[inst.alu.opcode]( cp, inst )) {
- return GL_FALSE;
- }
- }
-
- /* TODO: only for outputs:
- */
- for (j = 0; j < 8; j++) {
- if (cp->xmm[j].dirty)
- spill(cp, j);
- }
-
-
- /* Exit mmx state?
- */
- if (cp->func.need_emms)
- mmx_emms(&cp->func);
-
- /* Restore FPU control word?
- */
- if (cp->fpucntl != RESTORE_FPU) {
- x87_fnclex(&cp->func);
- x87_fldcw(&cp->func, x86_make_disp(regEDX, get_offset(m, &m->fpucntl_restore)));
- }
-
- x86_pop(&cp->func, regEBX);
- x86_ret(&cp->func);
-
- return GL_TRUE;
-}
-
-/**
- * Execute the given vertex program.
- *
- * TODO: Integrate the t_vertex.c code here, to build machine vertices
- * directly at this point.
- *
- * TODO: Eliminate the VB struct entirely and just use
- * struct arb_vertex_machine.
- */
-GLboolean
-_tnl_sse_codegen_vertex_program(struct tnl_compiled_program *p)
-{
- struct compilation cp;
-
- memset(&cp, 0, sizeof(cp));
- cp.p = p;
- cp.have_sse2 = 1;
-
- if (p->compiled_func) {
- _mesa_free((void *)p->compiled_func);
- p->compiled_func = NULL;
- }
-
- x86_init_func(&cp.func);
-
- cp.fpucntl = RESTORE_FPU;
-
-
- /* Note ctx state is not referenced in building the function, so it
- * depends only on the list of instructions:
- */
- if (!build_vertex_program(&cp)) {
- x86_release_func( &cp.func );
- return GL_FALSE;
- }
-
-
- p->compiled_func = (void (*)(struct arb_vp_machine *))x86_get_func( &cp.func );
- return GL_TRUE;
-}
-
-
-
-#else
-
-GLboolean
-_tnl_sse_codegen_vertex_program(struct tnl_compiled_program *p)
-{
- /* Dummy version for when USE_SSE_ASM not defined */
- return GL_FALSE;
-}
-
-#endif