diff options
author | David S. Miller <[email protected]> | 2009-02-26 05:35:15 -0800 |
---|---|---|
committer | Brian Paul <[email protected]> | 2009-02-26 18:29:48 -0700 |
commit | 857ac1e817808f4b6bf985679162d0e3d709e5b5 (patch) | |
tree | d023570b1faaa91088d05111aaebe98e7c424d27 /src/mesa/glapi/glapi.c | |
parent | b12dc74f86c611483465c08504dc8a564f927b15 (diff) |
mesa: Resurrect SPARC asm code.
This rewrites the sparc GLAPI code so that it's PIC friendly and works
with all of the TLS/PTHREADS/64-bit/32-bit combinations properly.
As a result we can turn SPARC asm back on. Currently it's only
enabled on Linux, as that's the only place where I can test this
stuff out.
For the moment the cliptest SPARC asm routines are disabled as they
are non-working. The problem is that they use register %g7 as a
temporary which is where the threading libraries store the thread
pointer on SPARC. I will fix that code up in a future change as it's
a pretty important routine to optimize.
Like x86 we do the runtime patch as a pthread once-invoked initializer
in init_glapi_relocs().
Unlike x86, however, our GLAPI stubs on SPARC are just two instruction
sequences that branch to a trampoline and put the GLAPI offset into a
register. The trampoline is what we run-time patch. The stubs thus
all look like:
glFoo:
ba __glapi_sparc_foo_stub
sethi GLAPI_OFFSET(glFOO) * PTR_SIZE, %g3
This actually makes generate_entrypoint() a lot simpler on SPARC. For
this case in generate_entrypoint() we generate stubs using a 'call'
instead of the 'ba' above to make sure it can reach.
In order to get a proper tail call going here, in the unpatched case,
we do several tricks. To get the current PC, for example, we save the
return address register into a temporary, do a call, save the return
address register written by the call to another temporary, then
restore the original return address register value. This is to
avoid having to allocate a stack frame.
This is necessary for PIC address formation.
This new GLAPI scheme lets us get rid of the ugly SPARC GLAPI hacks in
__glXInitialize() and one_time_init().
Signed-off-by: David S. Miller <[email protected]>
Diffstat (limited to 'src/mesa/glapi/glapi.c')
-rw-r--r-- | src/mesa/glapi/glapi.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/src/mesa/glapi/glapi.c b/src/mesa/glapi/glapi.c index e20618abc1d..2b105d0f17d 100644 --- a/src/mesa/glapi/glapi.c +++ b/src/mesa/glapi/glapi.c @@ -318,6 +318,14 @@ extern const GLubyte gl_dispatch_functions_start[]; # endif #endif +#ifdef USE_SPARC_ASM +#ifdef GLX_USE_TLS +extern unsigned int __glapi_sparc_tls_stub; +#else +extern unsigned int __glapi_sparc_pthread_stub; +#endif +#endif + #if !defined(DISPATCH_FUNCTION_SIZE) && !defined(XFree86Server) && !defined(XGLServer) # define NEED_FUNCTION_POINTER #endif @@ -344,6 +352,129 @@ init_glapi_relocs( void ) curr_func += DISPATCH_FUNCTION_SIZE; } #endif +#ifdef USE_SPARC_ASM + extern void __glapi_sparc_icache_flush(unsigned int *); + static const unsigned int template[] = { +#ifdef GLX_USE_TLS + 0x05000000, /* sethi %hi(_glapi_tls_Dispatch), %g2 */ + 0x8730e00a, /* srl %g3, 10, %g3 */ + 0x8410a000, /* or %g2, %lo(_glapi_tls_Dispatch), %g2 */ +#ifdef __arch64__ + 0xc259c002, /* ldx [%g7 + %g2], %g1 */ + 0xc2584003, /* ldx [%g1 + %g3], %g1 */ +#else + 0xc201c002, /* ld [%g7 + %g2], %g1 */ + 0xc2004003, /* ld [%g1 + %g3], %g1 */ +#endif + 0x81c04000, /* jmp %g1 */ + 0x01000000, /* nop */ +#else +#ifdef __arch64__ + 0x03000000, /* 64-bit 0x00 --> sethi %hh(_glapi_Dispatch), %g1 */ + 0x05000000, /* 64-bit 0x04 --> sethi %lm(_glapi_Dispatch), %g2 */ + 0x82106000, /* 64-bit 0x08 --> or %g1, %hm(_glapi_Dispatch), %g1 */ + 0x8730e00a, /* 64-bit 0x0c --> srl %g3, 10, %g3 */ + 0x83287020, /* 64-bit 0x10 --> sllx %g1, 32, %g1 */ + 0x82004002, /* 64-bit 0x14 --> add %g1, %g2, %g1 */ + 0xc2586000, /* 64-bit 0x18 --> ldx [%g1 + %lo(_glapi_Dispatch)], %g1 */ +#else + 0x03000000, /* 32-bit 0x00 --> sethi %hi(_glapi_Dispatch), %g1 */ + 0x8730e00a, /* 32-bit 0x04 --> srl %g3, 10, %g3 */ + 0xc2006000, /* 32-bit 0x08 --> ld [%g1 + %lo(_glapi_Dispatch)], %g1 */ +#endif + 0x80a06000, /* --> cmp %g1, 0 */ + 0x02800005, /* --> be +4*5 */ + 0x01000000, /* --> nop */ +#ifdef __arch64__ + 0xc2584003, /* 64-bit --> ldx [%g1 + %g3], %g1 */ +#else + 0xc2004003, /* 32-bit --> ld [%g1 + %g3], %g1 */ +#endif + 0x81c04000, /* --> jmp %g1 */ + 0x01000000, /* --> nop */ +#ifdef __arch64__ + 0x9de3bf80, /* 64-bit --> save %sp, -128, %sp */ +#else + 0x9de3bfc0, /* 32-bit --> save %sp, -64, %sp */ +#endif + 0xa0100003, /* --> mov %g3, %l0 */ + 0x40000000, /* --> call _glapi_get_dispatch */ + 0x01000000, /* --> nop */ + 0x82100008, /* --> mov %o0, %g1 */ + 0x86100010, /* --> mov %l0, %g3 */ + 0x10bffff7, /* --> ba -4*9 */ + 0x81e80000, /* --> restore */ +#endif + }; +#ifdef GLX_USE_TLS + extern unsigned long __glapi_sparc_get_dispatch(void); + unsigned int *code = &__glapi_sparc_tls_stub; + unsigned long dispatch = __glapi_sparc_get_dispatch(); +#else + unsigned int *code = &__glapi_sparc_pthread_stub; + unsigned long dispatch = (unsigned long) &_glapi_Dispatch; + unsigned long call_dest = (unsigned long ) &_glapi_get_dispatch; + int idx; +#endif + +#if defined(GLX_USE_TLS) + code[0] = template[0] | (dispatch >> 10); + code[1] = template[1]; + __glapi_sparc_icache_flush(&code[0]); + code[2] = template[2] | (dispatch & 0x3ff); + code[3] = template[3]; + __glapi_sparc_icache_flush(&code[2]); + code[4] = template[4]; + code[5] = template[5]; + __glapi_sparc_icache_flush(&code[4]); + code[6] = template[6]; + __glapi_sparc_icache_flush(&code[6]); +#else +#if defined(__arch64__) + code[0] = template[0] | (dispatch >> (32 + 10)); + code[1] = template[1] | ((dispatch & 0xffffffff) >> 10); + __glapi_sparc_icache_flush(&code[0]); + code[2] = template[2] | ((dispatch >> 32) & 0x3ff); + code[3] = template[3]; + __glapi_sparc_icache_flush(&code[2]); + code[4] = template[4]; + code[5] = template[5]; + __glapi_sparc_icache_flush(&code[4]); + code[6] = template[6] | (dispatch & 0x3ff); + idx = 7; +#else + code[0] = template[0] | (dispatch >> 10); + code[1] = template[1]; + __glapi_sparc_icache_flush(&code[0]); + code[2] = template[2] | (dispatch & 0x3ff); + idx = 3; +#endif + code[idx + 0] = template[idx + 0]; + __glapi_sparc_icache_flush(&code[idx - 1]); + code[idx + 1] = template[idx + 1]; + code[idx + 2] = template[idx + 2]; + __glapi_sparc_icache_flush(&code[idx + 1]); + code[idx + 3] = template[idx + 3]; + code[idx + 4] = template[idx + 4]; + __glapi_sparc_icache_flush(&code[idx + 3]); + code[idx + 5] = template[idx + 5]; + code[idx + 6] = template[idx + 6]; + __glapi_sparc_icache_flush(&code[idx + 5]); + code[idx + 7] = template[idx + 7]; + code[idx + 8] = template[idx + 8] | + (((call_dest - ((unsigned long) &code[idx + 8])) + >> 2) & 0x3fffffff); + __glapi_sparc_icache_flush(&code[idx + 7]); + code[idx + 9] = template[idx + 9]; + code[idx + 10] = template[idx + 10]; + __glapi_sparc_icache_flush(&code[idx + 9]); + code[idx + 11] = template[idx + 11]; + code[idx + 12] = template[idx + 12]; + __glapi_sparc_icache_flush(&code[idx + 11]); + code[idx + 13] = template[idx + 13]; + __glapi_sparc_icache_flush(&code[idx + 13]); +#endif +#endif } #endif /* defined(PTHREADS) || defined(GLX_USE_TLS) */ |