From 9b99a54e34219e6d0d9973909109cb6df5661585 Mon Sep 17 00:00:00 2001 From: asmodai Date: Sat, 17 Oct 2015 23:21:36 +0300 Subject: [PATCH] Added optimized stdlib functions from Agner's asmlib Increased allowed string commands rate --- rehlds/build.gradle | 4 +- rehlds/engine/common.h | 22 +-- rehlds/engine/sv_main.cpp | 34 ++--- rehlds/lib/libacof32.lib | Bin 0 -> 53338 bytes rehlds/lib/linux32/libaelf32.a | Bin 0 -> 69278 bytes rehlds/msvc/ReHLDS.vcxproj | 2 +- rehlds/public/asmlib.h | 224 ++++++++++++++++++++++++++++ rehlds/public/rehlds/sys_shared.cpp | 16 +- rehlds/rehlds/precompiled.h | 1 + rehlds/rehlds/rehlds_security.cpp | 6 +- 10 files changed, 262 insertions(+), 47 deletions(-) create mode 100644 rehlds/lib/libacof32.lib create mode 100644 rehlds/lib/linux32/libaelf32.a create mode 100644 rehlds/public/asmlib.h diff --git a/rehlds/build.gradle b/rehlds/build.gradle index 7a26462..e059cda 100644 --- a/rehlds/build.gradle +++ b/rehlds/build.gradle @@ -142,7 +142,7 @@ void setupToolchain(NativeBinarySpec b) { cfg.linkerOptions.baseAddress = '0x4970000' } cfg.projectLibpath(project, '/lib') - cfg.extraLibs 'steam_api.lib', 'psapi.lib', 'ws2_32.lib', 'kernel32.lib', 'user32.lib', 'advapi32.lib' + cfg.extraLibs 'steam_api.lib', 'psapi.lib', 'ws2_32.lib', 'kernel32.lib', 'user32.lib', 'advapi32.lib', 'libacof32.lib' } else if (cfg instanceof GccToolchainConfig) { cfg.compilerOptions.pchConfig = new GccToolchainConfig.PrecompilerHeaderOptions( enabled: true, @@ -158,7 +158,7 @@ void setupToolchain(NativeBinarySpec b) { ]) cfg.compilerOptions.args '-Qoption,cpp,--treat_func_as_string_literal_cpp', '-fno-rtti' cfg.projectLibpath(project, '/lib/linux32') - cfg.extraLibs 'rt', 'dl', 'm', 'steam_api' + cfg.extraLibs 'rt', 'dl', 'm', 'steam_api', 'aelf32' } if (!unitTestExecutable && !swdsLib) { diff --git a/rehlds/engine/common.h b/rehlds/engine/common.h index 5c2f2f2..2b6d205 100644 --- a/rehlds/engine/common.h +++ b/rehlds/engine/common.h @@ -117,26 +117,26 @@ extern int loadsize; #define _strlwr(p) for (int i = 0; p[i] != 0; i++) p[i] = tolower(p[i]); #endif -#define Q_memset memset -#define Q_memcpy memcpy -#define Q_memmove memmove -#define Q_strlen strlen -#define Q_memcmp memcmp -#define Q_strcpy strcpy +#define Q_memset A_memset +#define Q_memcpy A_memcpy +#define Q_memmove A_memmove +#define Q_strlen A_strlen +#define Q_memcmp A_memcmp +#define Q_strcpy A_strcpy #define Q_strncpy strncpy #define Q_strrchr strrchr -#define Q_strcat strcat +#define Q_strcat A_strcat #define Q_strncat strncat -#define Q_strcmp strcmp +#define Q_strcmp A_strcmp #define Q_strncmp strncmp //#define Q_strcasecmp _stricmp // Use Q_stricmp //#define Q_strncasecmp _strnicmp // Use Q_strnicmp -#define Q_stricmp _stricmp +#define Q_stricmp A_stricmp #define Q_strnicmp _strnicmp -#define Q_strstr strstr +#define Q_strstr A_strstr #define Q_strchr strchr #define Q_strrchr strrchr -#define Q_strlwr _strlwr +#define Q_strlwr A_strtolower #define Q_sprintf sprintf #define Q_snprintf _snprintf #define Q_atoi atoi diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp index 3471c85..9548b56 100644 --- a/rehlds/engine/sv_main.cpp +++ b/rehlds/engine/sv_main.cpp @@ -6440,7 +6440,7 @@ void SV_FailDownload(const char *filename) //----------------------------------------------------------------------------- // Finds a string in another string with a case insensitive test //----------------------------------------------------------------------------- -const char *Q_stristr(const char *pStr, const char *pSearch) +/*const char *Q_stristr(const char *pStr, const char *pSearch) { if (!pStr || !pSearch) return NULL; @@ -6478,7 +6478,7 @@ const char *Q_stristr(const char *pStr, const char *pSearch) } return NULL; -} +}*/ /* ../engine/sv_main.c:8736 */ qboolean IsSafeFileToDownload(const char *filename) @@ -6516,21 +6516,21 @@ qboolean IsSafeFileToDownload(const char *filename) || first != last || !first || Q_strlen(first) != 4 - || Q_stristr(lwrfilename, ".cfg") - || Q_stristr(lwrfilename, ".lst") - || Q_stristr(lwrfilename, ".exe") - || Q_stristr(lwrfilename, ".vbs") - || Q_stristr(lwrfilename, ".com") - || Q_stristr(lwrfilename, ".bat") - || Q_stristr(lwrfilename, ".dll") - || Q_stristr(lwrfilename, ".ini") - || Q_stristr(lwrfilename, ".log") - || Q_stristr(lwrfilename, "halflife.wad") - || Q_stristr(lwrfilename, "pak0.pak") - || Q_stristr(lwrfilename, "xeno.wad") - || Q_stristr(lwrfilename, ".so") - || Q_stristr(lwrfilename, ".dylib") - || Q_stristr(lwrfilename, ".sys")) + || Q_strstr(lwrfilename, ".cfg") + || Q_strstr(lwrfilename, ".lst") + || Q_strstr(lwrfilename, ".exe") + || Q_strstr(lwrfilename, ".vbs") + || Q_strstr(lwrfilename, ".com") + || Q_strstr(lwrfilename, ".bat") + || Q_strstr(lwrfilename, ".dll") + || Q_strstr(lwrfilename, ".ini") + || Q_strstr(lwrfilename, ".log") + || Q_strstr(lwrfilename, "halflife.wad") + || Q_strstr(lwrfilename, "pak0.pak") + || Q_strstr(lwrfilename, "xeno.wad") + || Q_strstr(lwrfilename, ".so") + || Q_strstr(lwrfilename, ".dylib") + || Q_strstr(lwrfilename, ".sys")) { return FALSE; } diff --git a/rehlds/lib/libacof32.lib b/rehlds/lib/libacof32.lib new file mode 100644 index 0000000000000000000000000000000000000000..f4cf15bdb4e2fbf32bab787b21a3d1cc02f41685 GIT binary patch literal 53338 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

?unTC(nq-hrOr#Gb6!8 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 WA&7CzGiC8ewJxPyroY!)dH*j3Klgb6 literal 0 HcmV?d00001 diff --git a/rehlds/msvc/ReHLDS.vcxproj b/rehlds/msvc/ReHLDS.vcxproj index 834c912..d437a29 100644 --- a/rehlds/msvc/ReHLDS.vcxproj +++ b/rehlds/msvc/ReHLDS.vcxproj @@ -769,7 +769,7 @@ true - psapi.lib;ws2_32.lib;$(ProjectDir)../lib/steam_api.lib;%(AdditionalDependencies) + psapi.lib;ws2_32.lib;$(ProjectDir)../lib/steam_api.lib;$(ProjectDir)../lib/libacof32.lib;%(AdditionalDependencies) diff --git a/rehlds/public/asmlib.h b/rehlds/public/asmlib.h new file mode 100644 index 0000000..d95d13d --- /dev/null +++ b/rehlds/public/asmlib.h @@ -0,0 +1,224 @@ +/*************************** asmlib.h *************************************** +* Author: Agner Fog +* Date created: 2003-12-12 +* Last modified: 2013-10-04 +* Project: asmlib.zip +* Source URL: www.agner.org/optimize +* +* Description: +* Header file for the asmlib function library. +* This library is available in many versions for different platforms. +* See asmlib-instructions.pdf for details. +* +* (c) Copyright 2003 - 2013 by Agner Fog. +* GNU General Public License http://www.gnu.org/licenses/gpl.html +*****************************************************************************/ + + +#ifndef ASMLIB_H +#define ASMLIB_H + + +/*********************************************************************** +Define compiler-specific types and directives +***********************************************************************/ + +// Define type size_t +#ifndef _SIZE_T_DEFINED +#include "stddef.h" +#endif + +// Define integer types with known size: int32_t, uint32_t, int64_t, uint64_t. +// If this doesn't work then insert compiler-specific definitions here: +#if defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1600) + // Compilers supporting C99 or C++0x have stdint.h defining these integer types + #include + #define INT64_SUPPORTED // Remove this if the compiler doesn't support 64-bit integers +#elif defined(_MSC_VER) + // Older Microsoft compilers have their own definition + typedef signed __int16 int16_t; + typedef unsigned __int16 uint16_t; + typedef signed __int32 int32_t; + typedef unsigned __int32 uint32_t; + typedef signed __int64 int64_t; + typedef unsigned __int64 uint64_t; + #define INT64_SUPPORTED // Remove this if the compiler doesn't support 64-bit integers +#else + // This works with most compilers + typedef signed short int int16_t; + typedef unsigned short int uint16_t; + typedef signed int int32_t; + typedef unsigned int uint32_t; + typedef long long int64_t; + typedef unsigned long long uint64_t; + #define INT64_SUPPORTED // Remove this if the compiler doesn't support 64-bit integers +#endif + + +// Turn off name mangling +#ifdef __cplusplus +extern "C" { +#endif + +/*********************************************************************** +Function prototypes, memory and string functions +***********************************************************************/ +void * A_memcpy (void * dest, const void * src, size_t count); // Copy count bytes from src to dest +void * A_memmove(void * dest, const void * src, size_t count); // Same as memcpy, allows overlap between src and dest +void * A_memset (void * dest, int c, size_t count); // Set count bytes in dest to (char)c +int A_memcmp (const void * buf1, const void * buf2, size_t num); // Compares two blocks of memory +size_t GetMemcpyCacheLimit(void); // Data blocks bigger than this will be copied uncached by memcpy and memmove +void SetMemcpyCacheLimit(size_t); // Change limit in GetMemcpyCacheLimit +size_t GetMemsetCacheLimit(void); // Data blocks bigger than this will be stored uncached by memset +void SetMemsetCacheLimit(size_t); // Change limit in GetMemsetCacheLimit +char * A_strcat (char * dest, const char * src); // Concatenate strings dest and src. Store result in dest +char * A_strcpy (char * dest, const char * src); // Copy string src to dest +size_t A_strlen (const char * str); // Get length of zero-terminated string +int A_strcmp (const char * a, const char * b); // Compare strings. Case sensitive +int A_stricmp (const char *string1, const char *string2); // Compare strings. Case insensitive for A-Z only +char * A_strstr (char * haystack, const char * needle); // Search for substring in string +void A_strtolower(char * string); // Convert string to lower case for A-Z only +void A_strtoupper(char * string); // Convert string to upper case for a-z only +size_t A_substring(char * dest, const char * source, size_t pos, size_t len); // Copy a substring for source into dest +size_t A_strspn (const char * str, const char * set); // Find span of characters that belong to set +size_t A_strcspn(const char * str, const char * set); // Find span of characters that don't belong to set +size_t strCountInSet(const char * str, const char * set); // Count characters that belong to set +size_t strcount_UTF8(const char * str); // Counts the number of characters in a UTF-8 encoded string + + +/*********************************************************************** +Function prototypes, miscellaneous functions +***********************************************************************/ +uint32_t A_popcount(uint32_t x); // Count 1-bits in 32-bit integer +int RoundD (double x); // Round to nearest or even +int RoundF (float x); // Round to nearest or even +int InstructionSet(void); // Tell which instruction set is supported +char * ProcessorName(void); // ASCIIZ text describing microprocessor +void CpuType(int * vendor, int * family, int * model); // Get CPU vendor, family and model +size_t DataCacheSize(int level); // Get size of data cache +void A_DebugBreak(void); // Makes a debug breakpoint +#ifdef INT64_SUPPORTED + uint64_t ReadTSC(void); // Read microprocessor internal clock (64 bits) +#else + uint32_t ReadTSC(void); // Read microprocessor internal clock (only 32 bits supported by compiler) +#endif +void cpuid_ex (int abcd[4], int eax, int ecx); // call CPUID instruction +static inline void cpuid_abcd (int abcd[4], int eax) { + cpuid_ex(abcd, eax, 0);} + +#ifdef __cplusplus +} // end of extern "C" + +// Define overloaded versions if compiling as C++ + +static inline int Round (double x) { // Overload name Round + return RoundD(x);} +static inline int Round (float x) { // Overload name Round + return RoundF(x);} +static inline const char * A_strstr(const char * haystack, const char * needle) { + return A_strstr((char*)haystack, needle);} // Overload A_strstr with const char * version + +#endif // __cplusplus + + +/*********************************************************************** +Function prototypes, integer division functions +***********************************************************************/ + +// Turn off name mangling +#ifdef __cplusplus +extern "C" { +#endif + +void setdivisori32(int buffer[2], int d); // Set divisor for repeated division +int dividefixedi32(const int buffer[2], int x); // Fast division with previously set divisor +void setdivisoru32(uint32_t buffer[2], uint32_t d); // Set divisor for repeated division +uint32_t dividefixedu32(const uint32_t buffer[2], uint32_t x); // Fast division with previously set divisor + +// Test if emmintrin.h is included and __m128i defined +#if defined(__GNUC__) && defined(_EMMINTRIN_H_INCLUDED) && !defined(__SSE2__) +#error Please compile with -sse2 or higher +#endif + +#if defined(_INCLUDED_EMM) || (defined(_EMMINTRIN_H_INCLUDED) && defined(__SSE2__)) +#define VECTORDIVISIONDEFINED + +// Integer vector division functions. These functions divide an integer vector by a scalar: + +// Set divisor for repeated integer vector division +void setdivisorV8i16(__m128i buf[2], int16_t d); // Set divisor for repeated division +void setdivisorV8u16(__m128i buf[2], uint16_t d); // Set divisor for repeated division +void setdivisorV4i32(__m128i buf[2], int32_t d); // Set divisor for repeated division +void setdivisorV4u32(__m128i buf[2], uint32_t d); // Set divisor for repeated division + +// Fast division of vector by previously set divisor +__m128i dividefixedV8i16(const __m128i buf[2], __m128i x); // Fast division with previously set divisor +__m128i dividefixedV8u16(const __m128i buf[2], __m128i x); // Fast division with previously set divisor +__m128i dividefixedV4i32(const __m128i buf[2], __m128i x); // Fast division with previously set divisor +__m128i dividefixedV4u32(const __m128i buf[2], __m128i x); // Fast division with previously set divisor + +#endif // defined(_INCLUDED_EMM) || (defined(_EMMINTRIN_H_INCLUDED) && defined(__SSE2__)) + +#ifdef __cplusplus +} // end of extern "C" +#endif // __cplusplus + +#ifdef __cplusplus + +// Define classes and operator '/' for fast division with fixed divisor +class div_i32; +class div_u32; +static inline int32_t operator / (int32_t x, div_i32 const &D); +static inline uint32_t operator / (uint32_t x, div_u32 const & D); + +class div_i32 { // Signed 32 bit integer division +public: + div_i32() { // Default constructor + buffer[0] = buffer[1] = 0; + } + div_i32(int d) { // Constructor with divisor + setdivisor(d); + } + void setdivisor(int d) { // Set divisor + setdivisori32(buffer, d); + } +protected: + int buffer[2]; // Internal memory + friend int32_t operator / (int32_t x, div_i32 const & D); +}; + +static inline int32_t operator / (int32_t x, div_i32 const &D){// Overloaded operator '/' + return dividefixedi32(D.buffer, x); +} + +static inline int32_t operator /= (int32_t &x, div_i32 const &D){// Overloaded operator '/=' + return x = x / D; +} + +class div_u32 { // Unsigned 32 bit integer division +public: + div_u32() { // Default constructor + buffer[0] = buffer[1] = 0; + } + div_u32(uint32_t d) { // Constructor with divisor + setdivisor(d); + } + void setdivisor(uint32_t d) { // Set divisor + setdivisoru32(buffer, d); + } +protected: + uint32_t buffer[2]; // Internal memory + friend uint32_t operator / (uint32_t x, div_u32 const & D); +}; + +static inline uint32_t operator / (uint32_t x, div_u32 const & D){ // Overloaded operator '/' + return dividefixedu32(D.buffer, x); +} + +static inline uint32_t operator /= (uint32_t &x, div_u32 const &D){// Overloaded operator '/=' + return x = x / D; +} + +#endif // __cplusplus + +#endif // ASMLIB_H diff --git a/rehlds/public/rehlds/sys_shared.cpp b/rehlds/public/rehlds/sys_shared.cpp index f39b79a..58981d6 100644 --- a/rehlds/public/rehlds/sys_shared.cpp +++ b/rehlds/public/rehlds/sys_shared.cpp @@ -42,14 +42,9 @@ cpuinfo_t cpuinfo; void Sys_CheckCpuInstructionsSupport(void) { - unsigned int cpuid_data[4]; + int cpuid_data[4]; - // eax = 1, ecx = 0 -#if defined(__GNUC__) - __get_cpuid(0x1, &cpuid_data[0], &cpuid_data[1], &cpuid_data[2], &cpuid_data[3]); -#else //__GNUC__ - __cpuidex((int*)cpuid_data, 1, 0); -#endif //__GNUC__ + cpuid_ex(cpuid_data, 1, 0); cpuinfo.sse3 = (cpuid_data[2] & SSE3_FLAG) ? 1 : 0; // ecx cpuinfo.ssse3 = (cpuid_data[2] & SSSE3_FLAG) ? 1 : 0; @@ -57,12 +52,7 @@ void Sys_CheckCpuInstructionsSupport(void) cpuinfo.sse4_2 = (cpuid_data[2] & SSE4_2_FLAG) ? 1 : 0; cpuinfo.avx = (cpuid_data[2] & AVX_FLAG) ? 1 : 0; - // eax = 7, ecx = 0 -#if defined(__GNUC__) - __get_cpuid(0x7, &cpuid_data[0], &cpuid_data[1], &cpuid_data[2], &cpuid_data[3]); -#else //__GNUC__ - __cpuidex((int*)cpuid_data, 7, 0); -#endif //__GNUC__ + cpuid_ex(cpuid_data, 7, 0); cpuinfo.avx2 = (cpuid_data[1] & AVX2_FLAG) ? 1 : 0; // ebx } \ No newline at end of file diff --git a/rehlds/rehlds/precompiled.h b/rehlds/rehlds/precompiled.h index 401c661..89439d8 100644 --- a/rehlds/rehlds/precompiled.h +++ b/rehlds/rehlds/precompiled.h @@ -5,6 +5,7 @@ #include "osconfig.h" #include "archtypes.h" +#include "asmlib.h" #include "mathlib.h" #include "sys_shared.h" diff --git a/rehlds/rehlds/rehlds_security.cpp b/rehlds/rehlds/rehlds_security.cpp index 92b339d..efbbc4c 100644 --- a/rehlds/rehlds/rehlds_security.cpp +++ b/rehlds/rehlds/rehlds_security.cpp @@ -1,9 +1,9 @@ #include "precompiled.h" cvar_t sv_rehlds_movecmdrate_max_avg = { "sv_rehlds_movecmdrate_max_avg", "750", 0, 750.0f, NULL }; -cvar_t sv_rehlds_movecmdrate_max_burst = { "sv_rehlds_movecmdrate_max_burst", "3500", 0, 3500.0f, NULL }; -cvar_t sv_rehlds_stringcmdrate_max_avg = {"sv_rehlds_stringcmdrate_max_avg", "32", 0, 32.0f, NULL}; -cvar_t sv_rehlds_stringcmdrate_max_burst = {"sv_rehlds_stringcmdrate_max_burst", "80", 0, 80.0f, NULL}; +cvar_t sv_rehlds_movecmdrate_max_burst = { "sv_rehlds_movecmdrate_max_burst", "1125", 0, 1125.0f, NULL }; +cvar_t sv_rehlds_stringcmdrate_max_avg = {"sv_rehlds_stringcmdrate_max_avg", "64", 0, 32.0f, NULL}; +cvar_t sv_rehlds_stringcmdrate_max_burst = {"sv_rehlds_stringcmdrate_max_burst", "96", 0, 80.0f, NULL}; CMoveCommandRateLimiter g_MoveCommandRateLimiter; CStringCommandsRateLimiter g_StringCommandsRateLimiter;