📄 t_vb_arbprogram_sse.c
字号:
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -