experimental optimizer for float ops

This commit is contained in:
David Anderson 2006-02-10 15:43:27 +00:00
parent b527efde41
commit dcaf3066bf
14 changed files with 474 additions and 59 deletions

View File

@ -288,7 +288,7 @@ static cell AMX_NATIVE_CALL invalid_native(AMX *amx, cell *params)
}
char name[sNAMEMAX + 1];
int native = amx->usertags[UT_NATIVE];
int native = reinterpret_cast<int>(amx->usertags[UT_NATIVE]);
int err = amx_GetNative(amx, native, name);
if (err != AMX_ERR_NONE)

Binary file not shown.

Binary file not shown.

View File

@ -46,6 +46,7 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "osdefs.h"
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
#include <sclinux.h>
@ -265,6 +266,12 @@ typedef enum {
OP_SYSREQ_D,
OP_SYMTAG, /* obsolete */
OP_BREAK,
OP_FLOAT_MUL,
OP_FLOAT_DIV,
OP_FLOAT_ADD,
OP_FLOAT_SUB,
OP_FLOAT_TO,
OP_FLOAT_ROUND,
/* ----- */
OP_NUM_OPCODES
} OPCODE;
@ -444,7 +451,7 @@ int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params)
/* As of AMX Mod X 1.56, we don't patch sysreq.c to sysreq.d anymore.
* Otherwise, we'd have no way of knowing the last native to be used.
*/
amx->usertags[UT_NATIVE] = (long)index;
amx->usertags[UT_NATIVE] = (void *)index;
/* Note:
* params[0] == number of bytes for the additional parameters passed to the native function
@ -487,6 +494,7 @@ static int amx_BrowseRelocate(AMX *amx)
cell cip;
long codesize;
OPCODE op;
BROWSEHOOK hook = NULL;
#if defined __GNUC__ || defined ASM32 || defined JIT
cell *opcode_list;
#endif
@ -502,6 +510,7 @@ static int amx_BrowseRelocate(AMX *amx)
code=amx->base+(int)hdr->cod;
codesize=hdr->dat - hdr->cod;
amx->flags|=AMX_FLAG_BROWSE;
hook = (BROWSEHOOK)amx->usertags[UT_BROWSEHOOK];
/* sanity checks */
assert(OP_PUSH_PRI==36);
@ -607,11 +616,22 @@ static int amx_BrowseRelocate(AMX *amx)
case OP_FILL:
case OP_HALT:
case OP_BOUNDS:
case OP_SYSREQ_C:
case OP_PUSHADDR:
case OP_SYSREQ_D:
cip+=sizeof(cell);
break;
case OP_SYSREQ_C:
{
if (hook)
#if defined __GNUC__ || defined ASM32 || defined JIT
hook(amx, opcode_list, &cip);
#else
hook(amx, NULL, &cip);
#endif
else
cip+=sizeof(cell);
break;
}
case OP_LOAD_I: /* instructions without parameters */
case OP_STOR_I:
@ -672,6 +692,12 @@ static int amx_BrowseRelocate(AMX *amx)
case OP_SWAP_ALT:
case OP_NOP:
case OP_BREAK:
case OP_FLOAT_MUL:
case OP_FLOAT_DIV:
case OP_FLOAT_ADD:
case OP_FLOAT_SUB:
case OP_FLOAT_TO:
case OP_FLOAT_ROUND:
break;
case OP_CALL: /* opcodes that need relocation */
@ -799,6 +825,7 @@ static void expand(unsigned char *code, long codesize, long memsize)
int AMXAPI amx_Init(AMX *amx, void *program)
{
AMX_HEADER *hdr;
BROWSEHOOK hook = NULL;
#if (defined _Windows || defined LINUX || defined __FreeBSD__ || defined __OpenBSD__) && !defined AMX_NODYNALOAD
char libname[sNAMEMAX+8]; /* +1 for '\0', +3 for 'amx' prefix, +4 for extension */
#if defined _Windows
@ -946,6 +973,9 @@ int AMXAPI amx_Init(AMX *amx,void *program)
#endif
/* relocate call and jump instructions */
hook = (BROWSEHOOK)amx->usertags[UT_BROWSEHOOK];
if (hook)
hook(amx, NULL, NULL);
amx_BrowseRelocate(amx);
/* load any extension modules that the AMX refers to */
@ -1259,27 +1289,22 @@ int AMXAPI amx_GetNative(AMX *amx, int index, char *funcname)
int AMXAPI amx_FindNative(AMX *amx, const char *name, int *index)
{
int first,last,mid,result;
int first,last,mid;
char pname[sNAMEMAX+1];
amx_NumNatives(amx, &last);
last--; /* last valid index is 1 less than the number of functions */
first=0;
/* binary search */
while (first<=last) {
mid=(first+last)/2;
/* normal search */
for (mid=0; mid<=last; mid++)
{
amx_GetNative(amx, mid, pname);
result=strcmp(pname,name);
if (result>0) {
last=mid-1;
} else if (result<0) {
first=mid+1;
} else {
if (strcmp(pname, name)==0)
{
*index = mid;
return AMX_ERR_NONE;
} /* if */
} /* while */
/* not found, set to an invalid index, so amx_Exec() will fail */
} /* for */
*index=INT_MAX;
return AMX_ERR_NOTFOUND;
}
@ -1492,37 +1517,11 @@ int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname)
#if defined AMX_XXXUSERDATA
int AMXAPI amx_GetUserData(AMX *amx, long tag, void **ptr)
{
int index;
assert(amx!=NULL);
assert(tag!=0);
for (index=0; index<AMX_USERNUM && amx->usertags[index]!=tag; index++)
/* nothing */;
if (index>=AMX_USERNUM)
return AMX_ERR_USERDATA;
*ptr=amx->userdata[index];
return AMX_ERR_NONE;
}
int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr)
{
int index;
assert(amx!=NULL);
assert(tag!=0);
/* try to find existing tag */
for (index=0; index<AMX_USERNUM && amx->usertags[index]!=tag; index++)
/* nothing */;
/* if not found, try to find empty tag */
if (index>=AMX_USERNUM)
for (index=0; index<AMX_USERNUM && amx->usertags[index]!=0; index++)
/* nothing */;
/* if still not found, quit with error */
if (index>=AMX_USERNUM)
return AMX_ERR_INDEX;
/* set the tag and the value */
amx->usertags[index]=tag;
amx->userdata[index]=ptr;
return AMX_ERR_NONE;
}
#endif /* AMX_XXXUSERDATA */
@ -1764,13 +1763,15 @@ static const void * const amx_opcodelist[] = {
&&op_file, &&op_line, &&op_symbol, &&op_srange,
&&op_jump_pri, &&op_switch, &&op_casetbl, &&op_swap_pri,
&&op_swap_alt, &&op_pushaddr, &&op_nop, &&op_sysreq_d,
&&op_symtag, &&op_break };
&&op_symtag, &&op_break, &&op_float_mul, &&op_float_div,
&&op_float_add, &&op_float_sub, &&op_float_to, &&op_float_round};
AMX_HEADER *hdr;
AMX_FUNCSTUB *func;
unsigned char *code, *data;
cell pri,alt,stk,frm,hea;
cell reset_stk, reset_hea, *cip;
cell offs;
cell offs, offs2;
REAL fnum;
ucell codesize;
int num,i;
@ -2616,6 +2617,47 @@ static const void * const amx_opcodelist[] = {
NEXT(cip);
op_nop:
NEXT(cip);
op_float_mul:
offs = *(cell *)(data + (int)stk + sizeof(cell)*1);
offs2 = *(cell *)(data + (int)stk + sizeof(cell)*2);
fnum = amx_ctof(offs) * amx_ctof(offs2);
pri = amx_ftoc(fnum);
NEXT(cip);
op_float_add:
offs = *(cell *)(data + (int)stk + sizeof(cell)*1);
offs2 = *(cell *)(data + (int)stk + sizeof(cell)*2);
fnum = amx_ctof(offs) + amx_ctof(offs2);
pri = amx_ftoc(fnum);
NEXT(cip);
op_float_sub:
offs = *(cell *)(data + (int)stk + sizeof(cell)*1);
offs2 = *(cell *)(data + (int)stk + sizeof(cell)*2);
fnum = amx_ctof(offs) - amx_ctof(offs2);
pri = amx_ftoc(fnum);
NEXT(cip);
op_float_div:
offs = *(cell *)(data + (int)stk + sizeof(cell)*1);
offs2 = *(cell *)(data + (int)stk + sizeof(cell)*2);
fnum = amx_ctof(offs) / amx_ctof(offs2);
pri = amx_ftoc(fnum);
NEXT(cip);
op_float_to:
offs = *(cell *)(data + (int)stk + sizeof(cell)*1);
fnum = (REAL)offs;
pri = amx_ftoc(fnum);
NEXT(cip);
op_float_round:
offs = *(cell *)(data + (int)stk + sizeof(cell)*1);
offs2 = *(cell *)(data + (int)stk + sizeof(cell)*2);
fnum = amx_ctof(offs);
if (!offs2)
fnum = floor(fnum + 0.5);
else if (offs2 == 1)
fnum = floor(fnum);
else
fnum = ceil(fnum);
pri = (cell)fnum;
NEXT(cip);
op_break:
if (amx->debug!=NULL) {
/* store status */
@ -2700,7 +2742,8 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index)
cell parms[9]; /* registers and parameters for assembler AMX */
#else
OPCODE op;
cell offs;
cell offs, offs2;
REAL fnum;
int num;
#endif
assert(amx!=NULL);
@ -3590,6 +3633,47 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index)
PUSH(frm+offs);
break;
case OP_NOP:
break;
case OP_FLOAT_MUL:
offs = *(cell *)(data + (int)stk + sizeof(cell)*1);
offs2 = *(cell *)(data + (int)stk + sizeof(cell)*2);
fnum = amx_ctof(offs) * amx_ctof(offs2);
pri = amx_ftoc(fnum);
break;
case OP_FLOAT_ADD:
offs = *(cell *)(data + (int)stk + sizeof(cell)*1);
offs2 = *(cell *)(data + (int)stk + sizeof(cell)*2);
fnum = amx_ctof(offs) + amx_ctof(offs2);
pri = amx_ftoc(fnum);
break;
case OP_FLOAT_SUB:
offs = *(cell *)(data + (int)stk + sizeof(cell)*1);
offs2 = *(cell *)(data + (int)stk + sizeof(cell)*2);
fnum = amx_ctof(offs) - amx_ctof(offs2);
pri = amx_ftoc(fnum);
break;
case OP_FLOAT_DIV:
offs = *(cell *)(data + (int)stk + sizeof(cell)*1);
offs2 = *(cell *)(data + (int)stk + sizeof(cell)*2);
fnum = amx_ctof(offs) / amx_ctof(offs2);
pri = amx_ftoc(fnum);
break;
case OP_FLOAT_TO:
offs = *(cell *)(data + (int)stk + sizeof(cell)*1);
fnum = (float)offs;
pri = amx_ftoc(fnum);
break;
case OP_FLOAT_ROUND:
offs = *(cell *)(data + (int)stk + sizeof(cell)*1);
offs2 = *(cell *)(data + (int)stk + sizeof(cell)*2);
fnum = amx_ctof(offs);
if (!offs2)
fnum = (REAL)floor(fnum + 0.5);
else if (offs2 == 1)
fnum = floor(fnum);
else
fnum = ceil(fnum);
pri = (cell)fnum;
break;
case OP_BREAK:
assert((amx->flags & AMX_FLAG_BROWSE)==0);

View File

@ -231,7 +231,7 @@ typedef struct tagAMX {
cell stp PACKED; /* top of the stack: relative to base + amxhdr->dat */
int flags PACKED; /* current status, see amx_Flags() */
/* user data */
long usertags[AMX_USERNUM] PACKED;
void _FAR *usertags[AMX_USERNUM] PACKED;
//okay userdata[3] in AMX Mod X is for the CPlugin * pointer
//we're also gonna set userdata[2] to a special debug structure
//lastly, userdata[1] is for opcode_list from amx_BrowseRelocate
@ -334,6 +334,10 @@ enum {
#define UD_OPCODELIST 1
#define UD_HANDLER 0
#define UT_NATIVE 3
#define UT_OPTIMIZER 2
#define UT_BROWSEHOOK 1
typedef void (*BROWSEHOOK)(AMX *amx, cell *oplist, cell *cip);
/* for native functions that use floating point parameters, the following
* two macros are convenient for casting a "cell" into a "float" type _without_

View File

@ -267,6 +267,28 @@ int AMXAPI dbg_LookupLine(AMX_DBG *amxdbg, ucell address, long *line)
return AMX_ERR_NONE;
}
void AMXAPI dbg_DumpFuncs(AMX_DBG *amxdbg, const char *file)
{
int index;
FILE *fp = fopen(file, "at");
if (!fp)
return;
for (index=0; index<amxdbg->hdr->symbols; index++)
{
if (amxdbg->symboltbl[index]->ident == iFUNCTN)
{
fprintf(fp, "[%s] --> (%d-%d)",
amxdbg->symboltbl[index]->name,
amxdbg->symboltbl[index]->codestart,
amxdbg->symboltbl[index]->codeend);
}
}
fclose(fp);
}
int AMXAPI dbg_LookupFunction(AMX_DBG *amxdbg, ucell address, const char **funcname)
{
/* dbg_LookupFunction() finds the function a code address is in. It can be

View File

@ -56,6 +56,8 @@
;
;History (list of changes)
;-------------------------
; 10 february 2006 by David Anderson
; Addition of float opcodes
; 17 february 2005 by Thiadmer Riemersms
; Addition of the BREAK opcode, removal of the older debugging opcode table.
; 6 march 2004 by Thiadmer Riemersma
@ -1406,6 +1408,83 @@ OP_NOP:
add esi,4
GO_ON
OP_FLOAT_MUL:
add esi,4
fld dword [edi+ecx+4]
fmul dword [edi+ecx+8]
push dword 0
fstp dword [esp]
pop eax
GO_ON
OP_FLOAT_DIV:
add esi,4
fld dword [edi+ecx+4]
fdiv dword [edi+ecx+8]
push dword 0
fstp dword [esp]
pop eax
GO_ON
OP_FLOAT_ADD:
add esi,4
fld dword [edi+ecx+4]
fadd dword [edi+ecx+8]
push dword 0
fstp dword [esp]
pop eax
GO_ON
OP_FLOAT_SUB:
add esi,4
fld dword [edi+ecx+4]
fsub dword [edi+ecx+8]
push dword 0
fstp dword [esp]
pop eax
GO_ON
OP_FLOAT_TO:
add esi,4
fild dword [edi+ecx+4]
push 0
fstp dword [esp]
pop eax
GO_ON
OP_FLOAT_ROUND:
add esi,4
;get the float control word
push 0
mov ebp,esp
fstcw [ebp]
mov eax,[ebp]
push eax
;clear the top bits
xor ah,ah
;get the control method
push edx
mov edx,[edi+ecx+8]
and edx,3 ;sanity check
shl edx,2 ;shift it to right position
;set the bits
or ah,dl ;set bits 15,14 of FCW to rounding method
or ah,3 ;set precision to 64bit
mov [ebp], eax
fldcw [ebp]
;calculate
push 0
fld dword [edi+ecx+4]
frndint
fistp dword [esp]
pop eax
pop edx
;restore bits
pop ebp
mov [esp], ebp
fldcw [esp]
pop ebp
GO_ON
OP_BREAK:
mov ebp,amx ; get amx into ebp
@ -1642,4 +1721,9 @@ _amx_opcodelist DD OP_INVALID
DD OP_SYSREQ_D
DD OP_SYMTAG
DD OP_BREAK
DD OP_FLOAT_MUL
DD OP_FLOAT_DIV
DD OP_FLOAT_ADD
DD OP_FLOAT_SUB
DD OP_FLOAT_TO
DD OP_FLOAT_ROUND

View File

@ -1882,7 +1882,7 @@ OP_BREAK:
jae code_gen_done
jmp DWORD [ebx] ; go on with the next opcode
%else
GO_ON j_break, OP_INVALID
GO_ON j_break, OP_FLOAT_MUL
j_break:
mov ebp,amx
cmp DWORD [ebp+_debug], 0
@ -1891,6 +1891,90 @@ OP_BREAK:
CHECKCODESIZE j_break
%endif
OP_FLOAT_MUL:
GO_ON j_float_mul, OP_FLOAT_DIV
j_float_mul:
fld dword [esi+4]
fmul dword [esi+8]
push dword 0
fstp dword [esp]
pop eax
CHECKCODESIZE j_float_mul
OP_FLOAT_DIV:
GO_ON j_float_div, OP_FLOAT_ADD
j_float_div:
fld dword [esi+4]
fdiv dword [esi+8]
push dword 0
fstp dword [esp]
pop eax
CHECKCODESIZE j_float_div
OP_FLOAT_ADD:
GO_ON j_float_add, OP_FLOAT_SUB
j_float_add:
fld dword [esi+4]
fadd dword [esi+8]
push dword 0
fstp dword [esp]
pop eax
CHECKCODESIZE j_float_add
OP_FLOAT_SUB:
GO_ON j_float_sub, OP_FLOAT_TO
j_float_sub:
fld dword [esi+4]
fsub dword [esi+8]
push dword 0
fstp dword [esp]
pop eax
CHECKCODESIZE j_float_sub
OP_FLOAT_TO:
GO_ON j_float_to, OP_FLOAT_ROUND
j_float_to:
fild dword [esi+4]
push 0
fstp dword [esp]
pop eax
CHECKCODESIZE j_float_to
OP_FLOAT_ROUND:
GO_ON j_float_round, OP_INVALID
j_float_round:
;get the float control word
push 0
mov ebp,esp
fstcw [ebp]
mov eax,[ebp]
push eax
;clear the top bits
xor ah,ah
;get the control method
push edx
mov edx,[esi+8]
and edx,3 ;sanity check
shl edx,2 ;shift it to right position
;set the bits
or ah,dl ;set bits 15,14 of FCW to rounding method
or ah,3 ;set precision to 64bit
mov [ebp], eax
fldcw [ebp]
;calculate
push 0
fld dword [esi+4]
frndint
fistp dword [esp]
pop eax
pop edx
;restore bits
pop ebp
mov [esp], ebp
fldcw [esp]
pop ebp
CHECKCODESIZE j_float_round
OP_INVALID: ; break from the compiler with an error code
mov eax,AMX_ERR_INVINSTR
pop esi
@ -2461,5 +2545,11 @@ _amx_opcodelist_jit:
DD OP_SYSREQ_D ; TR
DD OP_SYMTAG ; TR
DD OP_BREAK ; TR
DD OP_FLOAT_MUL ; DA
DD OP_FLOAT_DIV ; DA
DD OP_FLOAT_ADD ; DA
DD OP_FLOAT_SUB ; DA
DD OP_FLOAT_TO ; DA
DD OP_FLOAT_ROUND ; DA
END

View File

@ -442,7 +442,7 @@ int Debugger::FormatError(char *buffer, size_t maxLength)
num = (int)*p_cip;
}*/
//New code only requires this...
num = m_pAmx->usertags[UT_NATIVE];
num = (int)m_pAmx->usertags[UT_NATIVE];
amx_err = amx_GetNative(m_pAmx, num, native_name);
/*if (num)
amx_err = amx_GetNative(m_pAmx, (int)*p_cip, native_name);

View File

@ -44,6 +44,7 @@
#include "newmenus.h"
#include "natives.h"
#include "debugger.h"
#include "optimizer.h"
CList<CModule, const char*> g_modules;
CList<CScript, AMX*> g_loadedscripts;
@ -100,6 +101,8 @@ void free_amxmemory(void **ptr)
*ptr = 0;
}
void AMXAPI dbg_DumpFuncs(AMX_DBG *amxdbg, const char *file);
int load_amxscript(AMX *amx, void **program, const char *filename, char error[64], int debug)
{
*error = 0;
@ -197,6 +200,8 @@ int load_amxscript(AMX *amx, void **program, const char *filename, char error[64
return (amx->error = AMX_ERR_INIT);
}
dbg_DumpFuncs(pDbg, "c:\\test.txt");
amx->flags |= AMX_FLAG_DEBUG;
} else {
sprintf(error, "Plugin not compiled with debug option");
@ -209,6 +214,8 @@ int load_amxscript(AMX *amx, void **program, const char *filename, char error[64
#endif
}
SetupOptimizer(amx);
if ((err = amx_Init(amx, *program)) != AMX_ERR_NONE)
{
if (pDbg)

View File

@ -1,6 +0,0 @@
LIBRARY amxx_mm
EXPORTS
GiveFnptrsToDll @1
SECTIONS
.data READ WRITE

View File

@ -686,6 +686,9 @@
<File
RelativePath="..\newmenus.cpp">
</File>
<File
RelativePath="..\optimizer.cpp">
</File>
<File
RelativePath="..\power.cpp">
</File>
@ -835,6 +838,9 @@
<File
RelativePath="..\newmenus.h">
</File>
<File
RelativePath="..\optimizer.h">
</File>
<File
RelativePath="..\resource.h">
</File>

100
amxmodx/optimizer.cpp Normal file
View File

@ -0,0 +1,100 @@
#include <string.h>
#include "optimizer.h"
#define OP_SYSREQ_C 123
#define OP_NOP 134
#define OP_FLOAT_MUL 138
#define OP_FLOAT_DIV 139
#define OP_FLOAT_ADD 140
#define OP_FLOAT_SUB 141
#define OP_FLOAT_TO 142
#define OP_FLOAT_ROUND 143
cell op_trans_table[N_Total_FloatOps] =
{
OP_FLOAT_MUL,
OP_FLOAT_DIV,
OP_FLOAT_ADD,
OP_FLOAT_SUB,
OP_FLOAT_TO,
OP_FLOAT_ROUND
};
void OnBrowseRelocate(AMX *amx, cell *oplist, cell *cip)
{
char *codeptr = (char *)amx->base + (long)(((AMX_HEADER *)amx->base)->cod);
//jump to the parameter;
codeptr += *cip;
int native = -1;
cell n_offs = *(cell *)codeptr;
optimizer_s *opt = (optimizer_s *)amx->usertags[UT_OPTIMIZER];
for (int i=0; i<N_Total_FloatOps; i++)
{
if (opt->natives[i] == n_offs)
{
native = i;
break;
}
}
if (native != -1)
{
//we're patching this:
// 0x7B 0x?? SYSREQ.C float???
//with:
// 0x8A FLOAT.MUL
// 0x86 NOP
cell new_opcodes[2];
new_opcodes[0] = op_trans_table[native];
new_opcodes[1] = OP_NOP;
codeptr -= sizeof(cell);
#if defined __GNUC__ || defined ASM32 || defined JIT
*(cell *)codeptr = oplist[new_opcodes[0]];
*(cell *)(codeptr + sizeof(cell)) = oplist[new_opcodes[1]];
#else
*(cell *)codeptr = new_opcodes[0];
*(cell *)(codeptr + sizeof(cell)) = new_opcodes[1];
#endif
}
*cip += sizeof(cell);
return;
}
#define FIND_NATIVE(name, bind) \
if (amx_FindNative(amx, name, &index) != AMX_ERR_NOTFOUND) \
opt->natives[bind] = index;
void _Setup_Optimizer_Stage2(AMX *amx, cell *oplist, cell *cip)
{
int index;
amx->usertags[UT_BROWSEHOOK] = (void *)OnBrowseRelocate;
optimizer_s *opt = new optimizer_s;
for (int i=0; i<N_Total_FloatOps; i++)
opt->natives[i] = -1;
amx->usertags[UT_OPTIMIZER] = (void *)opt;
FIND_NATIVE("floatmul", N_Float_Mul);
FIND_NATIVE("floatdiv", N_Float_Div);
FIND_NATIVE("floatadd", N_Float_Add);
FIND_NATIVE("floatsub", N_Float_Sub);
FIND_NATIVE("float", N_Float_To);
FIND_NATIVE("floatround", N_Float_Round);
//we don't do these yet because of radix stuff >:\
//FIND_NATIVE("floatsin", N_Float_Sin);
//FIND_NATIVE("floatcos", N_Float_Cos);
//FIND_NATIVE("floattan", N_Float_Tan);
}
void SetupOptimizer(AMX *amx)
{
amx->usertags[UT_BROWSEHOOK] = (void *)_Setup_Optimizer_Stage2;
}

24
amxmodx/optimizer.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef _INCLUDE_AMXMODX_OPTIMIZER_H
#define _INCLUDE_AMXMODX_OPTIMIZER_H
#include "amx.h"
enum
{
N_Float_Mul=0,
N_Float_Div,
N_Float_Add,
N_Float_Sub,
N_Float_To,
N_Float_Round,
N_Total_FloatOps
};
struct optimizer_s
{
int natives[N_Total_FloatOps];
};
void SetupOptimizer(AMX *amx);
#endif //_INCLUDE_AMXMODX_OPTIMIZER_H