- Enable backpatching for VC++ builds of ZDBSP.

SVN r2411 (trunk)
This commit is contained in:
Randy Heit 2010-07-05 04:18:37 +00:00
parent 2de2b094ec
commit 08216817e5
3 changed files with 47 additions and 6 deletions

View file

@ -31,11 +31,15 @@ if( CMAKE_SIZEOF_VOID_P MATCHES "4" )
endif( CMAKE_SIZEOF_VOID_P MATCHES "4" )
if( SSE_MATTERS )
if( CMAKE_COMPILER_IS_GNUCXX AND WIN32 )
if( WIN32 )
set( BACKPATCH 1 CACHE BOOL "Enable backpatching." )
endif( CMAKE_COMPILER_IS_GNUCXX AND WIN32 )
else( WIN32 )
set( BACKPATCH 0 )
endif( WIN32 )
set( FULL_SSE2 0 CACHE BOOL "Use SSE2 math everywhere." )
set( SSE 1 CACHE BOOL "Build SSE and SSE2 versions of key code." )
else( SSE_MATTERS )
set( BACKPATCH 0 )
endif( SSE_MATTERS )
if( CMAKE_COMPILER_IS_GNUCXX )
@ -99,6 +103,10 @@ else( ZLIB_FOUND )
set( ZLIB_LIBRARY z )
endif( ZLIB_FOUND )
if( BACKPATCH )
add_definitions( -DBACKPATCH )
endif( BACKPATCH )
CHECK_FUNCTION_EXISTS( stricmp STRICMP_EXISTS )
if( NOT STRICMP_EXISTS )
add_definitions( -Dstricmp=strcasecmp )

View file

@ -1053,19 +1053,29 @@ void FNodeBuilder::PrintSet (int l, DWORD set)
Printf ("*\n");
}
#if defined(_WIN32) && !defined(__SSE2__) && !defined(DISABLE_SSE) && !defined(DISABLE_BACKPATCH) && defined(__i386__) && defined(__GNUC__)
#ifdef BACKPATCH
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#ifdef __GNUC__
extern "C" int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
#else
static int *CallerOffset;
int ClassifyLineBackpatchC (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
#endif
{
// Select the routine based on SSELevel and patch the caller so that
// they call that routine directly next time instead of going through here.
int *calleroffset = (int *)__builtin_return_address(0) - 1;
int *calleroffset;
int diff;
int (*func)(node_t &, const FSimpleVert *, const FSimpleVert *, int[2]);
DWORD oldprotect;
#ifdef __GNUC__
calleroffset = (int *)__builtin_return_address(0) - 1;
#else
calleroffset = CallerOffset;
#endif
// printf ("Patching for SSE %d\n", SSELevel);
if (SSELevel == 2)
@ -1094,4 +1104,23 @@ extern "C" int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const
// And return by calling the real function.
return func (node, v1, v2, sidev);
}
#ifndef __GNUC__
// The ClassifyLineBackpatch() function here is a stub that uses inline assembly and nakedness
// to retrieve the return address of the stack before sending control to the real
// ClassifyLineBackpatchC() function. Since BACKPATCH shouldn't be defined on 64-bit builds,
// we're okay that VC++ can't do inline assembly on that target.
extern "C" __declspec(noinline) __declspec(naked) int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
{
// We store the return address in a global, so as not to need to mess with the parameter list.
__asm
{
mov eax, [esp]
sub eax, 4
mov CallerOffset, eax
jmp ClassifyLineBackpatchC
}
}
#endif
#endif

View file

@ -56,8 +56,12 @@ extern "C"
#ifndef DISABLE_SSE
int ClassifyLineSSE1 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
int ClassifyLineSSE2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
#if defined(_WIN32) && defined(__GNUC__) && !defined(DISABLE_BACKPATCH)
#ifdef BACKPATCH
#ifdef __GNUC__
int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) __attribute__((noinline));
#else
int __declspec(noinline) ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
#endif
#endif
#endif
}
@ -300,7 +304,7 @@ inline int FNodeBuilder::ClassifyLine (node_t &node, const FPrivVert *v1, const
return ClassifyLine2 (node, v1, v2, sidev);
#else
// Select the routine based on our flag.
#if defined(_WIN32) && defined(__GNUC__) && !defined(DISABLE_BACKPATCH)
#ifdef BACKPATCH
return ClassifyLineBackpatch (node, v1, v2, sidev);
#else
if (SSELevel == 2)