Generates working SSE code for gears under the swrast driver.
This commit is contained in:
+137
-68
@@ -42,6 +42,8 @@
|
||||
#define Z 2
|
||||
#define W 3
|
||||
|
||||
#define DISASSEM 1
|
||||
|
||||
struct x86_reg {
|
||||
GLuint file:3;
|
||||
GLuint idx:3;
|
||||
@@ -144,6 +146,17 @@ static struct x86_reg make_disp( struct x86_reg reg,
|
||||
return reg;
|
||||
}
|
||||
|
||||
static struct x86_reg deref( struct x86_reg reg )
|
||||
{
|
||||
return make_disp(reg, 0);
|
||||
}
|
||||
|
||||
static struct x86_reg get_base_reg( struct x86_reg reg )
|
||||
{
|
||||
return make_reg( reg.file, reg.idx );
|
||||
}
|
||||
|
||||
|
||||
/* Retreive a reference to one of the function arguments, taking into
|
||||
* account any push/pop activity:
|
||||
*/
|
||||
@@ -179,30 +192,48 @@ static void emit_1b( struct x86_program *p, GLbyte b0 )
|
||||
*(GLbyte *)(p->csr++) = b0;
|
||||
}
|
||||
|
||||
static void emit_1ub( struct x86_program *p, GLubyte b0 )
|
||||
{
|
||||
*(p->csr++) = b0;
|
||||
}
|
||||
|
||||
static void emit_2ub( struct x86_program *p, GLubyte b0, GLubyte b1 )
|
||||
{
|
||||
*(p->csr++) = b0;
|
||||
*(p->csr++) = b1;
|
||||
}
|
||||
|
||||
static void emit_3ub( struct x86_program *p, GLubyte b0, GLubyte b1, GLubyte b2 )
|
||||
{
|
||||
*(p->csr++) = b0;
|
||||
*(p->csr++) = b1;
|
||||
*(p->csr++) = b2;
|
||||
}
|
||||
|
||||
static void emit_1i( struct x86_program *p, GLint i0 )
|
||||
{
|
||||
*(GLint *)(p->csr) = i0;
|
||||
p->csr += 4;
|
||||
}
|
||||
|
||||
static void disassem( struct x86_program *p, const char *fn )
|
||||
{
|
||||
#if DISASSEM
|
||||
static const char *last_fn;
|
||||
if (fn && fn != last_fn) {
|
||||
_mesa_printf("0x%x: %s\n", p->csr, fn);
|
||||
last_fn = fn;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void emit_1ub_fn( struct x86_program *p, GLubyte b0, const char *fn )
|
||||
{
|
||||
disassem(p, fn);
|
||||
*(p->csr++) = b0;
|
||||
}
|
||||
|
||||
static void emit_2ub_fn( struct x86_program *p, GLubyte b0, GLubyte b1, const char *fn )
|
||||
{
|
||||
disassem(p, fn);
|
||||
*(p->csr++) = b0;
|
||||
*(p->csr++) = b1;
|
||||
}
|
||||
|
||||
static void emit_3ub_fn( struct x86_program *p, GLubyte b0, GLubyte b1, GLubyte b2, const char *fn )
|
||||
{
|
||||
disassem(p, fn);
|
||||
*(p->csr++) = b0;
|
||||
*(p->csr++) = b1;
|
||||
*(p->csr++) = b2;
|
||||
}
|
||||
|
||||
#define emit_1ub(p, b0) emit_1ub_fn(p, b0, __FUNCTION__)
|
||||
#define emit_2ub(p, b0, b1) emit_2ub_fn(p, b0, b1, __FUNCTION__)
|
||||
#define emit_3ub(p, b0, b1, b2) emit_3ub_fn(p, b0, b1, b2, __FUNCTION__)
|
||||
|
||||
|
||||
/* Labels, jumps and fixup:
|
||||
*/
|
||||
@@ -216,7 +247,7 @@ static void emit_jcc( struct x86_program *p,
|
||||
GLubyte *label )
|
||||
{
|
||||
GLint offset = label - (get_label(p) + 2);
|
||||
|
||||
|
||||
if (offset <= 127 && offset >= -128) {
|
||||
emit_1ub(p, 0x70 + cc);
|
||||
emit_1b(p, (GLbyte) offset);
|
||||
@@ -273,7 +304,7 @@ static void emit_dec( struct x86_program *p,
|
||||
struct x86_reg reg )
|
||||
{
|
||||
assert(reg.mod == mod_REG);
|
||||
emit_1ub(p, 0x40 + reg.idx);
|
||||
emit_1ub(p, 0x48 + reg.idx);
|
||||
}
|
||||
|
||||
static void emit_ret( struct x86_program *p )
|
||||
@@ -299,7 +330,13 @@ static void emit_modrm( struct x86_program *p,
|
||||
val |= reg.idx << 3; /* reg field */
|
||||
val |= regmem.idx; /* r/m field */
|
||||
|
||||
emit_1ub(p, val);
|
||||
emit_1ub_fn(p, val, 0);
|
||||
|
||||
/* Oh-oh we've stumbled into the SIB thing.
|
||||
*/
|
||||
if (regmem.idx == reg_SP) {
|
||||
emit_1ub_fn(p, 0x24, 0); /* simplistic! */
|
||||
}
|
||||
|
||||
switch (regmem.mod) {
|
||||
case mod_REG:
|
||||
@@ -307,8 +344,10 @@ static void emit_modrm( struct x86_program *p,
|
||||
break;
|
||||
case mod_DISP8:
|
||||
emit_1b(p, regmem.disp);
|
||||
break;
|
||||
case mod_DISP32:
|
||||
emit_1i(p, regmem.disp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,14 +364,14 @@ static void emit_op_modrm( struct x86_program *p,
|
||||
{
|
||||
switch (dst.mod) {
|
||||
case mod_REG:
|
||||
emit_1ub(p, op_dst_is_reg);
|
||||
emit_1ub_fn(p, op_dst_is_reg, 0);
|
||||
emit_modrm(p, dst, src);
|
||||
break;
|
||||
case mod_INDIRECT:
|
||||
case mod_DISP32:
|
||||
case mod_DISP8:
|
||||
assert(src.mod == mod_REG);
|
||||
emit_1ub(p, op_dst_is_mem);
|
||||
emit_1ub_fn(p, op_dst_is_mem, 0);
|
||||
emit_modrm(p, src, dst);
|
||||
break;
|
||||
}
|
||||
@@ -352,6 +391,13 @@ static void emit_xor( struct x86_program *p,
|
||||
emit_op_modrm( p, 0x33, 0x31, dst, src );
|
||||
}
|
||||
|
||||
static void emit_cmp( struct x86_program *p,
|
||||
struct x86_reg dst,
|
||||
struct x86_reg src )
|
||||
{
|
||||
emit_op_modrm( p, 0x3b, 0x39, dst, src );
|
||||
}
|
||||
|
||||
static void emit_movlps( struct x86_program *p,
|
||||
struct x86_reg dst,
|
||||
struct x86_reg src )
|
||||
@@ -443,6 +489,14 @@ static void emit_packsswb( struct x86_program *p,
|
||||
emit_modrm( p, dst, src );
|
||||
}
|
||||
|
||||
static void emit_packuswb( struct x86_program *p,
|
||||
struct x86_reg dst,
|
||||
struct x86_reg src )
|
||||
{
|
||||
emit_3ub(p, 0x66, X86_TWOB, 0x67);
|
||||
emit_modrm( p, dst, src );
|
||||
}
|
||||
|
||||
/* Load effective address:
|
||||
*/
|
||||
static void emit_lea( struct x86_program *p,
|
||||
@@ -461,6 +515,14 @@ static void emit_add_imm( struct x86_program *p,
|
||||
emit_lea(p, dst, make_disp(src, value));
|
||||
}
|
||||
|
||||
static void emit_test( struct x86_program *p,
|
||||
struct x86_reg dst,
|
||||
struct x86_reg src )
|
||||
{
|
||||
emit_1ub(p, 0x85);
|
||||
emit_modrm( p, dst, src );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -487,7 +549,7 @@ static void emit_pk4ub( struct x86_program *p,
|
||||
{
|
||||
emit_cvtps2dq(p, dest, arg0);
|
||||
emit_packssdw(p, dest, dest);
|
||||
emit_packsswb(p, dest, dest);
|
||||
emit_packuswb(p, dest, dest);
|
||||
}
|
||||
|
||||
static void emit_load4f_4( struct x86_program *p,
|
||||
@@ -620,12 +682,12 @@ static void (*load[4][4])( struct x86_program *p,
|
||||
};
|
||||
|
||||
static void emit_load( struct x86_program *p,
|
||||
struct x86_reg temp,
|
||||
struct x86_reg dest,
|
||||
GLuint sz,
|
||||
struct x86_reg src,
|
||||
GLuint src_sz)
|
||||
{
|
||||
load[sz-1][src_sz-1](p, temp, src);
|
||||
load[sz-1][src_sz-1](p, dest, src);
|
||||
}
|
||||
|
||||
|
||||
@@ -721,6 +783,7 @@ static GLboolean build_vertex_emit( struct x86_program *p )
|
||||
struct x86_reg tmp = make_reg(file_XMM, 0);
|
||||
struct x86_reg vp0 = make_reg(file_XMM, 1);
|
||||
struct x86_reg vp1 = make_reg(file_XMM, 2);
|
||||
struct x86_reg chan0 = make_reg(file_XMM, 3);
|
||||
GLubyte *fixup, *label;
|
||||
|
||||
p->csr = p->store;
|
||||
@@ -731,6 +794,15 @@ static GLboolean build_vertex_emit( struct x86_program *p )
|
||||
emit_push(p, countEBP);
|
||||
emit_push(p, vtxESI);
|
||||
|
||||
|
||||
/* Get vertex count, compare to zero
|
||||
*/
|
||||
emit_xor(p, srcEDI, srcEDI);
|
||||
emit_mov(p, countEBP, make_fn_arg(p, 2));
|
||||
emit_cmp(p, countEBP, srcEDI);
|
||||
fixup = emit_jcc_forward(p, cc_E);
|
||||
|
||||
|
||||
/* Initialize destination register.
|
||||
*/
|
||||
emit_mov(p, vertexEAX, make_fn_arg(p, 3));
|
||||
@@ -741,10 +813,6 @@ static GLboolean build_vertex_emit( struct x86_program *p )
|
||||
emit_mov(p, vtxESI, make_disp(vtxESI, get_offset(ctx, &ctx->swtnl_context)));
|
||||
vtxESI = make_disp(vtxESI, get_offset(tnl, &tnl->clipspace));
|
||||
|
||||
/* Get vertex count, compare to zero
|
||||
*/
|
||||
emit_mov(p, countEBP, make_fn_arg(p, 2));
|
||||
fixup = emit_jcc_forward(p, cc_NZ);
|
||||
|
||||
/* Possibly load vp0, vp1 for viewport calcs:
|
||||
*/
|
||||
@@ -753,6 +821,10 @@ static GLboolean build_vertex_emit( struct x86_program *p )
|
||||
emit_movups(p, vp1, make_disp(vtxESI, get_offset(vtx, &vtx->vp_xlate[0])));
|
||||
}
|
||||
|
||||
/* always load, needed or not:
|
||||
*/
|
||||
emit_movups(p, chan0, make_disp(vtxESI, get_offset(vtx, &vtx->chan_scale[0])));
|
||||
|
||||
/* Note address for loop jump */
|
||||
label = get_label(p);
|
||||
|
||||
@@ -775,40 +847,40 @@ static GLboolean build_vertex_emit( struct x86_program *p )
|
||||
*/
|
||||
switch (a[j].format) {
|
||||
case EMIT_1F:
|
||||
emit_load(p, tmp, 1, srcEDI, vtx->attr[j].inputsize);
|
||||
emit_load(p, tmp, 1, deref(srcEDI), vtx->attr[j].inputsize);
|
||||
emit_store(p, dest, 1, tmp);
|
||||
case EMIT_2F:
|
||||
emit_load(p, tmp, 2, srcEDI, vtx->attr[j].inputsize);
|
||||
emit_load(p, tmp, 2, deref(srcEDI), vtx->attr[j].inputsize);
|
||||
emit_store(p, dest, 2, tmp);
|
||||
case EMIT_3F:
|
||||
/* Potentially the worst case - hardcode 2+1 copying:
|
||||
*/
|
||||
emit_load(p, tmp, 3, srcEDI, vtx->attr[j].inputsize);
|
||||
emit_load(p, tmp, 3, deref(srcEDI), vtx->attr[j].inputsize);
|
||||
emit_store(p, dest, 3, tmp);
|
||||
case EMIT_4F:
|
||||
emit_load(p, tmp, 4, srcEDI, vtx->attr[j].inputsize);
|
||||
emit_load(p, tmp, 4, deref(srcEDI), vtx->attr[j].inputsize);
|
||||
emit_store(p, dest, 4, tmp);
|
||||
break;
|
||||
case EMIT_2F_VIEWPORT:
|
||||
emit_load(p, tmp, 2, srcEDI, vtx->attr[j].inputsize);
|
||||
emit_mulps(p, dest, vp0);
|
||||
emit_addps(p, dest, vp1);
|
||||
emit_load(p, tmp, 2, deref(srcEDI), vtx->attr[j].inputsize);
|
||||
emit_mulps(p, tmp, vp0);
|
||||
emit_addps(p, tmp, vp1);
|
||||
emit_store(p, dest, 2, tmp);
|
||||
break;
|
||||
case EMIT_3F_VIEWPORT:
|
||||
emit_load(p, tmp, 3, srcEDI, vtx->attr[j].inputsize);
|
||||
emit_mulps(p, dest, vp0);
|
||||
emit_addps(p, dest, vp1);
|
||||
emit_load(p, tmp, 3, deref(srcEDI), vtx->attr[j].inputsize);
|
||||
emit_mulps(p, tmp, vp0);
|
||||
emit_addps(p, tmp, vp1);
|
||||
emit_store(p, dest, 3, tmp);
|
||||
break;
|
||||
case EMIT_4F_VIEWPORT:
|
||||
emit_load(p, tmp, 4, srcEDI, vtx->attr[j].inputsize);
|
||||
emit_mulps(p, dest, vp0);
|
||||
emit_addps(p, dest, vp1);
|
||||
emit_load(p, tmp, 4, deref(srcEDI), vtx->attr[j].inputsize);
|
||||
emit_mulps(p, tmp, vp0);
|
||||
emit_addps(p, tmp, vp1);
|
||||
emit_store(p, dest, 4, tmp);
|
||||
break;
|
||||
case EMIT_3F_XYW:
|
||||
emit_load(p, tmp, 4, srcEDI, vtx->attr[j].inputsize);
|
||||
emit_load(p, tmp, 4, deref(srcEDI), vtx->attr[j].inputsize);
|
||||
emit_pshufd(p, tmp, tmp, X, Y, W, Z);
|
||||
emit_store(p, dest, 3, tmp);
|
||||
break;
|
||||
@@ -818,48 +890,56 @@ static GLboolean build_vertex_emit( struct x86_program *p )
|
||||
case EMIT_1UB_1F:
|
||||
case EMIT_3UB_3F_RGB:
|
||||
case EMIT_3UB_3F_BGR:
|
||||
_mesa_printf("non-implemneted format %d\n", a[j].format);
|
||||
return GL_FALSE; /* add this later */
|
||||
|
||||
case EMIT_4UB_4F_RGBA:
|
||||
emit_load(p, tmp, 4, srcEDI, vtx->attr[j].inputsize);
|
||||
emit_load(p, tmp, 4, deref(srcEDI), vtx->attr[j].inputsize);
|
||||
emit_mulps(p, tmp, chan0);
|
||||
emit_pk4ub(p, tmp, tmp);
|
||||
emit_store(p, dest, 1, tmp);
|
||||
break;
|
||||
case EMIT_4UB_4F_BGRA:
|
||||
emit_load(p, tmp, 4, srcEDI, vtx->attr[j].inputsize);
|
||||
emit_load(p, tmp, 4, deref(srcEDI), vtx->attr[j].inputsize);
|
||||
emit_pshufd(p, tmp, tmp, Z, Y, X, W);
|
||||
emit_mulps(p, tmp, chan0);
|
||||
emit_pk4ub(p, tmp, tmp);
|
||||
emit_store(p, dest, 1, tmp);
|
||||
break;
|
||||
case EMIT_4UB_4F_ARGB:
|
||||
emit_load(p, tmp, 4, srcEDI, vtx->attr[j].inputsize);
|
||||
emit_load(p, tmp, 4, deref(srcEDI), vtx->attr[j].inputsize);
|
||||
emit_pshufd(p, tmp, tmp, W, X, Y, Z);
|
||||
emit_mulps(p, tmp, chan0);
|
||||
emit_pk4ub(p, tmp, tmp);
|
||||
emit_store(p, dest, 1, tmp);
|
||||
break;
|
||||
case EMIT_4UB_4F_ABGR:
|
||||
emit_load(p, tmp, 4, srcEDI, vtx->attr[j].inputsize);
|
||||
emit_load(p, tmp, 4, deref(srcEDI), vtx->attr[j].inputsize);
|
||||
emit_pshufd(p, tmp, tmp, W, Z, Y, X);
|
||||
emit_mulps(p, tmp, chan0);
|
||||
emit_pk4ub(p, tmp, tmp);
|
||||
emit_store(p, dest, 1, tmp);
|
||||
break;
|
||||
case EMIT_4CHAN_4F_RGBA:
|
||||
switch (CHAN_TYPE) {
|
||||
case GL_UNSIGNED_BYTE:
|
||||
emit_load(p, tmp, 4, srcEDI, vtx->attr[j].inputsize);
|
||||
emit_load(p, tmp, 4, deref(srcEDI), vtx->attr[j].inputsize);
|
||||
emit_mulps(p, tmp, chan0);
|
||||
emit_pk4ub(p, tmp, tmp);
|
||||
emit_store(p, dest, 1, tmp);
|
||||
break;
|
||||
case GL_UNSIGNED_SHORT:
|
||||
return GL_FALSE;
|
||||
case GL_FLOAT:
|
||||
emit_load(p, tmp, 4, srcEDI, vtx->attr[j].inputsize);
|
||||
emit_load(p, tmp, 4, deref(srcEDI), vtx->attr[j].inputsize);
|
||||
emit_store(p, dest, 4, tmp);
|
||||
break;
|
||||
case GL_UNSIGNED_SHORT:
|
||||
default:
|
||||
break;
|
||||
_mesa_printf("unknown CHAN_TYPE %s\n", _mesa_lookup_enum_by_nr(CHAN_TYPE));
|
||||
return GL_FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_mesa_printf("unknown a[%d].format %d\n", j, a[j].format);
|
||||
return GL_FALSE; /* catch any new opcodes */
|
||||
}
|
||||
|
||||
@@ -881,6 +961,7 @@ static GLboolean build_vertex_emit( struct x86_program *p )
|
||||
/* decr count, loop if not zero
|
||||
*/
|
||||
emit_dec(p, countEBP);
|
||||
emit_test(p, countEBP, countEBP);
|
||||
emit_jcc(p, cc_NZ, label);
|
||||
|
||||
/* Land forward jump here:
|
||||
@@ -889,7 +970,7 @@ static GLboolean build_vertex_emit( struct x86_program *p )
|
||||
|
||||
/* Pop regs and return
|
||||
*/
|
||||
emit_pop(p, vtxESI);
|
||||
emit_pop(p, get_base_reg(vtxESI));
|
||||
emit_pop(p, countEBP);
|
||||
emit_pop(p, srcEDI);
|
||||
emit_ret(p);
|
||||
@@ -912,20 +993,8 @@ void _tnl_generate_sse_emit( GLcontext *ctx )
|
||||
|
||||
if (build_vertex_emit(&p)) {
|
||||
_tnl_register_fastpath( vtx, GL_TRUE );
|
||||
|
||||
{
|
||||
static int i = 0;
|
||||
char filename[100];
|
||||
int fd;
|
||||
|
||||
sprintf(filename, "fastpath%d.o", i);
|
||||
fd = creat(filename, 0600);
|
||||
if (fd != -1) {
|
||||
write(fd, p.store, p.csr - p.store);
|
||||
close(fd);
|
||||
_mesa_printf("wrote %s\n", filename);
|
||||
}
|
||||
}
|
||||
if (DISASSEM)
|
||||
_mesa_printf("disassemble 0x%x 0x%x\n", p.store, p.csr);
|
||||
}
|
||||
else {
|
||||
FREE(p.store);
|
||||
|
||||
Reference in New Issue
Block a user