Fixed an issue with fteqw's pr_fixbrokenqccarrays cvar when used with mutators. Also fixed field remapping with regard to multiple fields with the same offsets.

Played around with classes a bit. Should work a bit better now.
Added an extra compiler flag, to allow for fast-tracking arrays in supported engines. It uses a global to detect it, but we don't yet set that global anywhere in the loader. This will probably have issues in DP.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@1325 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2005-09-14 04:36:07 +00:00
parent f1ec9f4952
commit 43a1890bcc
9 changed files with 138 additions and 50 deletions

View File

@ -388,6 +388,8 @@ reeval:
//get a pointer to a field var
case OP_ADDRESS:
if ((unsigned)OPA->edict >= maxedicts)
PR_RunError (progfuncs, "OP_ADDRESS references invalid entity in %s", progfuncs->stringtable + pr_xfunction->s_name);
ed = PROG_TO_EDICT(progfuncs, OPA->edict);
#ifdef PARANOID
NUM_FOR_EDICT(ed); // make sure it's in range
@ -407,6 +409,8 @@ reeval:
case OP_LOAD_ENT:
case OP_LOAD_S:
case OP_LOAD_FNC:
if ((unsigned)OPA->edict >= maxedicts)
PR_RunError (progfuncs, "OP_LOAD references invalid entity in %s", progfuncs->stringtable + pr_xfunction->s_name);
ed = PROG_TO_EDICT(progfuncs, OPA->edict);
#ifdef PARANOID
NUM_FOR_EDICT(ed); // make sure it's in range
@ -416,6 +420,8 @@ reeval:
break;
case OP_LOAD_V:
if ((unsigned)OPA->edict >= maxedicts)
PR_RunError (progfuncs, "OP_LOAD_V references invalid entity in %s", progfuncs->stringtable + pr_xfunction->s_name);
ed = PROG_TO_EDICT(progfuncs, OPA->edict);
#ifdef PARANOID
NUM_FOR_EDICT(ed); // make sure it's in range

View File

@ -360,7 +360,7 @@ typedef struct fdef_s
unsigned int type; // if DEF_SAVEGLOBAL bit is set
// the variable needs to be saved in savegames
unsigned int ofs;
unsigned int requestedofs;
unsigned int progsofs; //used at loading time, so maching field offsets (unions/members) are positioned at the same runtime offset.
char * name;
} fdef_t;

View File

@ -1439,28 +1439,13 @@ char *SaveCallStack (progfuncs_t *progfuncs, char *s)
sprintf(buffer, "\t\tofs%i %i // %f\n", f->parm_start+arg, *(int *)(globalbase - f->locals+arg), *(float *)(globalbase - f->locals+arg) );
else
{
//__try
//{
if (local->type == ev_entity)
{ //go safly.
int n;
sprintf(buffer, "\t\t\"%s\"\t\"entity INVALID POINTER\"\n", local->s_name+progfuncs->stringtable);
for (n = 0; n < sv_num_edicts; n++)
{
if (prinst->edicttable[n] == (struct edict_s *)PROG_TO_EDICT(progfuncs, ((eval_t*)(globalbase - f->locals+arg))->edict))
{
sprintf(buffer, "\t\t\"%s\" \"entity %i\"\n", local->s_name+progfuncs->stringtable, n);
break;
}
}
{
sprintf(buffer, "\t\t\"%s\" \"entity %i\"\n", local->s_name+progfuncs->stringtable, ((eval_t*)(globalbase - f->locals+arg))->edict);
}
else
sprintf(buffer, "\t\t\"%s\"\t\"%s\"\n", local->s_name+progfuncs->stringtable, PR_ValueString(progfuncs, local->type, (eval_t*)(globalbase - f->locals+arg)));
//}
//__except(EXCEPTION_EXECUTE_HANDLER)
//{
// sprintf(buffer, "\t\t\"%s\" \"ILLEGAL POINTER\"\n", local->s_name+progfuncs->stringtable);
//}
if (local->type == ev_vector)
arg+=2;
}
@ -2632,6 +2617,7 @@ retry:
if (reorg)
reorg = (headercrc != -1);
QC_FlushProgsOffsets(progfuncs);
switch(current_progstate->intsize)
{
case 24:
@ -2662,7 +2648,7 @@ retry:
else
type = fld16[i].type & ~(DEF_SHARED|DEF_SAVEGLOBAL);
if (progfuncs->fieldadjust) //we need to make sure all fields appear in thier original place.
if (progfuncs->fieldadjust && !pr_typecurrent) //we need to make sure all fields appear in thier original place.
QC_RegisterFieldVar(progfuncs, type, fld16[i].s_name+pr_strings, 4*(fld16[i].ofs+progfuncs->fieldadjust), -1);
else if (type == ev_vector) //emit vector vars early, so thier fields cannot be alocated before the vector itself. (useful against scramblers)
{
@ -2697,7 +2683,9 @@ retry:
type = pr_types[pr_fielddefs32[i].type & ~(DEF_SHARED|DEF_SAVEGLOBAL)].type;
else
type = pr_fielddefs32[i].type & ~(DEF_SHARED|DEF_SAVEGLOBAL);
if (type == ev_vector)
if (progfuncs->fieldadjust && !pr_typecurrent) //we need to make sure all fields appear in thier original place.
QC_RegisterFieldVar(progfuncs, type, fld16[i].s_name+pr_strings, 4*(fld16[i].ofs+progfuncs->fieldadjust), -1);
else if (type == ev_vector)
QC_RegisterFieldVar(progfuncs, type, pr_fielddefs32[i].s_name+pr_strings, -1, -1);
}
pr_fielddefs32[i].s_name += stringadjust;

View File

@ -212,7 +212,7 @@ void VARGS PR_RunError (progfuncs_t *progfuncs, char *error, ...)
// pr_depth = 0; // dump the stack so host_error can shutdown functions
// prinst->exitdepth = 0;
Abort (string);
Abort ("%s", string);
}
/*

View File

@ -180,13 +180,27 @@ void QC_InitShares(progfuncs_t *progfuncs)
progfuncs->fieldadjust = 0;
}
void QC_FlushProgsOffsets(progfuncs_t *progfuncs)
{ //sets the fields up for loading a new progs.
//fields are matched by name to other progs
//not by offset
unsigned int i;
for (i = 0; i < numfields; i++)
field[i].progsofs = -1;
}
//called if a global is defined as a field
//returns offset.
//vectors must be added before any of thier corresponding _x/y/z vars
//in this way, even screwed up progs work.
int QC_RegisterFieldVar(progfuncs_t *progfuncs, unsigned int type, char *name, int requestedpos, int originalofs)
//requestedpos is the offset the engine WILL put it at.
//origionaloffs is used to track matching field offsets. fields with the same progs offset overlap
//note: we probably suffer from progs with renamed system globals.
int QC_RegisterFieldVar(progfuncs_t *progfuncs, unsigned int type, char *name, int engineofs, int progsofs)
{
// progstate_t *p;
// int pnum;
@ -215,13 +229,13 @@ int QC_RegisterFieldVar(progfuncs_t *progfuncs, unsigned int type, char *name, i
printf("Field type mismatch on %s\n", name);
continue;
}
if (!progfuncs->fieldadjust && requestedpos>=0)
if ((unsigned)requestedpos != field[i].ofs)
if (!progfuncs->fieldadjust && engineofs>=0)
if ((unsigned)engineofs != field[i].ofs)
Sys_Error("Field %s at wrong offset", name);
if (field[i].requestedofs == -1)
field[i].requestedofs = originalofs;
return field[i].ofs; //got a match
if (field[i].progsofs == -1)
field[i].progsofs = progsofs;
return field[i].ofs-progfuncs->fieldadjust; //got a match
}
}
@ -240,29 +254,31 @@ int QC_RegisterFieldVar(progfuncs_t *progfuncs, unsigned int type, char *name, i
fnum = numfields;
numfields++;
field[fnum].name = name;
if (type == ev_vector) //resize with the following floats (this is where I think I went wrong)
if (type == ev_vector)
{
char *n;
namelen = strlen(name)+5;
n=PRHunkAlloc(progfuncs, namelen);
sprintf(n, "%s_x", name);
ofs = QC_RegisterFieldVar(progfuncs, ev_float, n, requestedpos, -1);
ofs = QC_RegisterFieldVar(progfuncs, ev_float, n, engineofs, progsofs);
field[fnum].ofs = ofs;
n=PRHunkAlloc(progfuncs, namelen);
sprintf(n, "%s_y", name);
QC_RegisterFieldVar(progfuncs, ev_float, n, (requestedpos==-1)?-1:(requestedpos+4), -1);
QC_RegisterFieldVar(progfuncs, ev_float, n, (engineofs==-1)?-1:(engineofs+4), (progsofs==-1)?-1:progsofs+1);
n=PRHunkAlloc(progfuncs, namelen);
sprintf(n, "%s_z", name);
QC_RegisterFieldVar(progfuncs, ev_float, n, (requestedpos==-1)?-1:(requestedpos+8), -1);
QC_RegisterFieldVar(progfuncs, ev_float, n, (engineofs==-1)?-1:(engineofs+8), (progsofs==-1)?-1:progsofs+2);
}
else if (requestedpos >= 0)
{
else if (engineofs >= 0)
{ //the engine is setting up a list of required field indexes.
//paranoid checking of the offset.
for (i = 0; i < numfields-1; i++)
{
if (field[i].ofs == (unsigned)requestedpos)
if (field[i].ofs == ((unsigned)engineofs)*4)
{
if (type == ev_float && field[i].type == ev_vector) //check names
{
@ -273,12 +289,27 @@ int QC_RegisterFieldVar(progfuncs_t *progfuncs, unsigned int type, char *name, i
Sys_Error("Duplicated offset");
}
}
if (requestedpos&3)
Sys_Error("field %s is %i&3", name, requestedpos);
field[fnum].ofs = ofs = requestedpos/4;
if (engineofs&3)
Sys_Error("field %s is %i&3", name, engineofs);
field[fnum].ofs = ofs = engineofs/4;
}
else
field[fnum].ofs = ofs = fields_size/4;
{ //we just found a new fieldname inside a progs
field[fnum].ofs = ofs = fields_size/4; //add on the end
//if the progs field offset matches annother offset in the same progs, make it match up with the earlier one.
if (progsofs>=0)
{
for (i = 0; i < numfields-1; i++)
{
if (field[i].progsofs == (unsigned)progsofs)
{
field[fnum].ofs = ofs = field[i].ofs;
break;
}
}
}
}
// if (type != ev_vector)
if (fields_size < (ofs+type_size[type])*4)
fields_size = (ofs+type_size[type])*4;
@ -287,10 +318,10 @@ int QC_RegisterFieldVar(progfuncs_t *progfuncs, unsigned int type, char *name, i
Sys_Error("Allocated too many additional fields after ents were inited.");
field[fnum].type = type;
field[fnum].requestedofs = originalofs;
field[fnum].progsofs = progsofs;
//we've finished setting the structure
return ofs;
return ofs - progfuncs->fieldadjust;
}
@ -326,7 +357,10 @@ void QC_AddSharedFieldVar(progfuncs_t *progfuncs, int num, char *stringtable)
{
if (!strcmp(pr_fielddefs16[i].s_name+stringtable, pr_globaldefs16[num].s_name+stringtable))
{
*(int *)&pr_globals[pr_globaldefs16[num].ofs] = QC_RegisterFieldVar(progfuncs, pr_fielddefs16[i].type, pr_globaldefs16[num].s_name+stringtable, -1, *(int *)&pr_globals[pr_globaldefs16[num].ofs])-progfuncs->fieldadjust;
int old = *(int *)&pr_globals[pr_globaldefs16[num].ofs];
*(int *)&pr_globals[pr_globaldefs16[num].ofs] = QC_RegisterFieldVar(progfuncs, pr_fielddefs16[i].type, pr_globaldefs16[num].s_name+stringtable, -1, *(int *)&pr_globals[pr_globaldefs16[num].ofs]);
printf("Field %s %i -> %i\n", pr_globaldefs16[num].s_name+stringtable, old, *(int *)&pr_globals[pr_globaldefs16[num].ofs]);
return;
}
}
@ -335,10 +369,12 @@ void QC_AddSharedFieldVar(progfuncs_t *progfuncs, int num, char *stringtable)
for (i = 0; i < numfields; i++)
{
o = field[i].requestedofs;
o = field[i].progsofs;
if (o == *(unsigned int *)&pr_globals[pr_globaldefs16[num].ofs])
{
int old = *(int *)&pr_globals[pr_globaldefs16[num].ofs];
*(int *)&pr_globals[pr_globaldefs16[num].ofs] = field[i].ofs-progfuncs->fieldadjust;
printf("Field %s %i -> %i\n", pr_globaldefs16[num].s_name+stringtable, old, *(int *)&pr_globals[pr_globaldefs16[num].ofs]);
return;
}
}
@ -352,7 +388,7 @@ void QC_AddSharedFieldVar(progfuncs_t *progfuncs, int num, char *stringtable)
{
if (!strcmp(pr_fielddefs32[i].s_name+stringtable, pr_globaldefs32[num].s_name+stringtable))
{
*(int *)&pr_globals[pr_globaldefs32[num].ofs] = QC_RegisterFieldVar(progfuncs, pr_fielddefs32[i].type, pr_globaldefs32[num].s_name+stringtable, -1, *(int *)&pr_globals[pr_globaldefs32[num].ofs])-progfuncs->fieldadjust;
*(int *)&pr_globals[pr_globaldefs32[num].ofs] = QC_RegisterFieldVar(progfuncs, pr_fielddefs32[i].type, pr_globaldefs32[num].s_name+stringtable, -1, *(int *)&pr_globals[pr_globaldefs32[num].ofs]);
return;
}
}
@ -361,7 +397,7 @@ void QC_AddSharedFieldVar(progfuncs_t *progfuncs, int num, char *stringtable)
for (i = 0; i < numfields; i++)
{
o = field[i].requestedofs;
o = field[i].progsofs;
if (o == *(unsigned int *)&pr_globals[pr_globaldefs32[num].ofs])
{
*(int *)&pr_globals[pr_globaldefs32[num].ofs] = field[i].ofs-progfuncs->fieldadjust;

View File

@ -476,6 +476,7 @@ extern pbool flag_acc;
extern pbool flag_caseinsensative;
extern pbool flag_laxcasts;
extern pbool flag_hashonly;
extern pbool flag_fasttrackarrays;
extern pbool opt_overlaptemps;
extern pbool opt_shortenifnots;

View File

@ -72,6 +72,7 @@ pbool flag_acc; //reacc like behaviour of src files (finds *.qc in start dir
pbool flag_caseinsensative; //symbols will be matched to an insensative case if the specified case doesn't exist. This should b usable for any mod
pbool flag_laxcasts; //Allow lax casting. This'll produce loadsa warnings of course. But allows compilation of certain dodgy code.
pbool flag_hashonly; //Allows use of only #constant for precompiler constants, allows certain preqcc using mods to compile
pbool flag_fasttrackarrays; //Faster arrays, dynamically detected, activated only in supporting engines.
pbool opt_overlaptemps; //reduce numpr_globals by reuse of temps. When they are not needed they are freed for reuse. The way this is implemented is better than frikqcc's. (This is the single most important optimisation)
pbool opt_assignments; //STORE_F isn't used if an operation wrote to a temp.
@ -3141,6 +3142,14 @@ void QCC_PR_EmitClassFromFunction(QCC_def_t *scope, char *tname)
if (!basetype)
QCC_PR_ParseError(ERR_INTERNAL, "Type %s was not defined...", tname);
pr_scope = NULL;
memset(basictypefield, 0, sizeof(basictypefield));
QCC_PR_EmitFieldsForMembers(basetype);
pr_scope = scope;
df = &functions[numfunctions];
@ -3184,10 +3193,7 @@ void QCC_PR_EmitClassFromFunction(QCC_def_t *scope, char *tname)
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_DONE], NULL, NULL, NULL));
pr_scope = NULL;
memset(basictypefield, 0, sizeof(basictypefield));
QCC_PR_EmitFieldsForMembers(basetype);
pr_scope = scope;
QCC_WriteAsmFunction(scope, df->first_statement, df->parm_start);
pr.localvars = NULL;
@ -6568,6 +6574,13 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, char *arrayname)
QCC_dstatement_t *st;
QCC_def_t *eq;
QCC_def_t *fasttrackpossible;
if (flag_fasttrackarrays)
fasttrackpossible = QCC_PR_GetDef(NULL, "__ext__fasttrackarrays", NULL, true, 1);
else
fasttrackpossible = NULL;
def = QCC_PR_GetDef(NULL, arrayname, NULL, false, 0);
if (def->arraysize >= 15 && def->type->size == 1)
@ -6592,6 +6605,22 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, char *arrayname)
G_FUNCTION(scope->ofs) = df - functions;
if (fasttrackpossible)
{
QCC_PR_Statement(pr_opcodes+OP_IFNOT, fasttrackpossible, NULL, &st);
//fetch_gbl takes: (float size, variant array[]), float index, variant pos
//note that the array size is coded into the globals, one index before the array.
def->ofs--;
if (def->type->size >= 3)
QCC_PR_Statement3(&pr_opcodes[OP_FETCH_GBL_V], def, index, &def_ret);
else
QCC_PR_Statement3(&pr_opcodes[OP_FETCH_GBL_F], def, index, &def_ret);
def->ofs++;
//finish the jump
st->b = &statements[numstatements] - st;
}
if (vectortrick)
{
QCC_def_t *div3, *intdiv3, *ret;
@ -6704,6 +6733,13 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, char *arrayname)
QCC_dfunction_t *df;
QCC_def_t *def, *index, *value;
QCC_def_t *fasttrackpossible;
if (flag_fasttrackarrays)
fasttrackpossible = QCC_PR_GetDef(NULL, "__ext__fasttrackarrays", NULL, true, 1);
else
fasttrackpossible = NULL;
def = QCC_PR_GetDef(NULL, arrayname, NULL, false, 0);
pr_scope = scope;
@ -6724,6 +6760,27 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, char *arrayname)
G_FUNCTION(scope->ofs) = df - functions;
if (fasttrackpossible)
{
QCC_dstatement_t *st;
QCC_PR_Statement(pr_opcodes+OP_IFNOT, fasttrackpossible, NULL, &st);
//note that the array size is coded into the globals, one index before the array.
QCC_PR_Statement3(&pr_opcodes[OP_CONV_FTOI], index, NULL, index); //address stuff is integer based, but standard qc (which this accelerates in supported engines) only supports floats
QCC_PR_SimpleStatement (OP_BOUNDCHECK, index->ofs, 0, ((int*)qcc_pr_globals)[def->ofs-1]);//annoy the programmer. :p
if (def->type->size != 1)//shift it upwards for larger types
QCC_PR_Statement3(&pr_opcodes[OP_MUL_I], index, QCC_MakeIntDef(def->type->size), index);
QCC_PR_Statement3(&pr_opcodes[OP_GLOBALADDRESS], def, index, index); //comes with built in add
if (def->type->size >= 3)
QCC_PR_Statement3(&pr_opcodes[OP_STOREP_V], value, index, NULL); //*b = a
else
QCC_PR_Statement3(&pr_opcodes[OP_STOREP_F], value, index, NULL);
//finish the jump
st->b = &statements[numstatements] - st;
}
QCC_PR_Statement3(pr_opcodes+OP_BITAND, index, index, index);
QCC_PR_ArraySetRecurseDivide(def, index, value, 0, def->arraysize);

View File

@ -555,7 +555,6 @@ pbool QCC_PR_Precompiler(void)
}
else if (!strncmp(directive, "include", 7))
{
int rellen;
char sm;
pr_file_p=directive+7;

View File

@ -221,6 +221,7 @@ compiler_flag_t compiler_flag[] = {
{&flag_laxcasts, FLAG_MIDCOMPILE,"lax", "Lax type checks", "Disables many errors (generating warnings instead) when function calls or operations refer to two normally incompatable types. This is required for reacc support, and can also allow certain (evil) mods to compile that were originally written for frikqcc."}, //Allow lax casting. This'll produce loadsa warnings of course. But allows compilation of certain dodgy code.
{&flag_hashonly, FLAG_MIDCOMPILE,"hashonly", "Hash-only constants", "Allows use of only #constant for precompiler constants, allows certain preqcc using mods to compile"},
{&opt_logicops, FLAG_MIDCOMPILE,"lo", "Logic ops", "This changes the behaviour of your code. It generates additional if operations to early-out in if statements. With this flag, the line if (0 && somefunction()) will never call the function. It can thus be considered an optimisation. However, due to the change of behaviour, it is not considered so by fteqcc. Note that due to inprecisions with floats, this flag can cause runaway loop errors within the player walk and run functions. This code is advised:\nplayer_stand1:\n if (self.velocity_x || self.velocity_y)\nplayer_run\n if (!(self.velocity_x || self.velocity_y))"},
{&flag_fasttrackarrays, FLAG_MIDCOMPILE,"fastarrays", "fast arrays where possible", "Generates extra instructions inside array handling functions to detect engine and use extension opcodes in supporting engines.\nAdds a global which is set by the engine if the engine supports the extra opcodes. Note that this applies to al lor none."}, //correction for if(string) no-ifstring to get the standard behaviour.
{NULL}
};