Fix some -TFTE issues with xonotic.

Implement OP_STOREF_F, but don't generate it just yet (waiting for next 'stable' build).
Just disable fteqcc.log by default. If this affects adversely you then you should probably just be using fteqccgui instead.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5698 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2020-05-30 12:12:46 +00:00
parent df5b4e4e48
commit 62a4572f23
8 changed files with 263 additions and 83 deletions

View File

@ -422,6 +422,102 @@ reeval:
*(unsigned char *)ptr = (char)OPA->_float; *(unsigned char *)ptr = (char)OPA->_float;
break; break;
case OP_STOREF_F:
case OP_STOREF_I:
case OP_STOREF_S:
errorif ((unsigned)OPA->edict >= (unsigned)num_edicts)
{
if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_STOREF_? references invalid entity in %s\n", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name)))
return prinst.pr_xstatement;
break;
}
ed = PROG_TO_EDICT_PB(progfuncs, OPA->edict);
#ifdef PARANOID
NUM_FOR_EDICT(ed); // make sure it's in range
#endif
errorif (!ed || ed->readonly)
{ //boot it over to the debugger
#if INTSIZE == 16
ddef16_t *d = ED_GlobalAtOfs16(progfuncs, st->a);
#else
ddef32_t *d = ED_GlobalAtOfs32(progfuncs, st->a);
#endif
fdef_t *f = ED_FieldAtOfs(progfuncs, OPB->_int + progfuncs->funcs.fieldadjust);
if (PR_ExecRunWarning(&progfuncs->funcs, st-pr_statements, "assignment to read-only entity %i in %s (%s.%s)\n", OPA->edict, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), d?PR_StringToNative(&progfuncs->funcs, d->s_name):"??", f?f->name:"??"))
return prinst.pr_xstatement;
break;
}
//Whilst the next block would technically be correct, we don't use it as it breaks too many quake mods.
#ifdef NOLEGACY
errorif (ed->ereftype == ER_FREE)
{
if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "assignment to free entity in %s", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name)))
return prinst.pr_xstatement;
break;
}
#endif
i = OPB->_int + progfuncs->funcs.fieldadjust;
errorif ((unsigned int)i*4 >= ed->fieldsize) //FIXME:lazy size check
{
if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_STOREF_? references invalid field %i in %s\n", OPB->_int, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name)))
return prinst.pr_xstatement;
break;
}
ptr = (eval_t *)(((int *)edvars(ed)) + i);
ptr->_int = OPC->_int;
break;
case OP_STOREF_V:
errorif ((unsigned)OPA->edict >= (unsigned)num_edicts)
{
if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_STOREF_? references invalid entity in %s\n", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name)))
return prinst.pr_xstatement;
break;
}
ed = PROG_TO_EDICT_PB(progfuncs, OPA->edict);
#ifdef PARANOID
NUM_FOR_EDICT(ed); // make sure it's in range
#endif
errorif (!ed || ed->readonly)
{ //boot it over to the debugger
#if INTSIZE == 16
ddef16_t *d = ED_GlobalAtOfs16(progfuncs, st->a);
#else
ddef32_t *d = ED_GlobalAtOfs32(progfuncs, st->a);
#endif
fdef_t *f = ED_FieldAtOfs(progfuncs, OPB->_int + progfuncs->funcs.fieldadjust);
if (PR_ExecRunWarning(&progfuncs->funcs, st-pr_statements, "assignment to read-only entity %i in %s (%s.%s)\n", OPA->edict, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), d?PR_StringToNative(&progfuncs->funcs, d->s_name):"??", f?f->name:"??"))
return prinst.pr_xstatement;
break;
}
//Whilst the next block would technically be correct, we don't use it as it breaks too many quake mods.
#ifdef NOLEGACY
errorif (ed->ereftype == ER_FREE)
{
if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "assignment to free entity in %s", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name)))
return prinst.pr_xstatement;
break;
}
#endif
i = OPB->_int + progfuncs->funcs.fieldadjust;
errorif ((unsigned int)i*4 >= ed->fieldsize) //FIXME:lazy size check
{
if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_STOREF_? references invalid field %i in %s\n", OPB->_int, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name)))
return prinst.pr_xstatement;
break;
}
ptr = (eval_t *)(((int *)edvars(ed)) + i);
ptr->_vector[0] = OPC->_vector[0];
ptr->_vector[1] = OPC->_vector[1];
ptr->_vector[2] = OPC->_vector[2];
break;
//get a pointer to a field var //get a pointer to a field var
case OP_ADDRESS: case OP_ADDRESS:
errorif ((unsigned)OPA->edict >= (unsigned)num_edicts) errorif ((unsigned)OPA->edict >= (unsigned)num_edicts)
@ -828,7 +924,7 @@ reeval:
case OP_LOADA_S: case OP_LOADA_S:
case OP_LOADA_FNC: case OP_LOADA_FNC:
i = st->a + OPB->_int; i = st->a + OPB->_int;
if ((size_t)(i<<2) >= (size_t)current_progstate->globals_size) if ((size_t)i >= (size_t)(current_progstate->globals_bytes>>2))
{ {
QCFAULT(&progfuncs->funcs, "bad array read in %s (index %i)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPB->_int); QCFAULT(&progfuncs->funcs, "bad array read in %s (index %i)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPB->_int);
} }
@ -838,7 +934,7 @@ reeval:
case OP_LOADA_V: case OP_LOADA_V:
i = st->a + OPB->_int; i = st->a + OPB->_int;
if ((size_t)(i<<2) >= (size_t)current_progstate->globals_size) if ((size_t)(i) >= (size_t)(current_progstate->globals_bytes>>2)-2u)
{ {
QCFAULT(&progfuncs->funcs, "bad array read in %s (index %i)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPB->_int); QCFAULT(&progfuncs->funcs, "bad array read in %s (index %i)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPB->_int);
} }
@ -1267,19 +1363,19 @@ reeval:
case OP_GLOAD_ENT: case OP_GLOAD_ENT:
case OP_GLOAD_S: case OP_GLOAD_S:
case OP_GLOAD_FNC: case OP_GLOAD_FNC:
errorif (OPA->_int < 0 || OPA->_int*4 >= current_progstate->globals_size) errorif (OPA->_int < 0 || OPA->_int >= (current_progstate->globals_bytes>>2))
{ {
prinst.pr_xstatement = st-pr_statements; prinst.pr_xstatement = st-pr_statements;
PR_RunError (&progfuncs->funcs, "bad indexed global read in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPA->_int, current_progstate->globals_size); PR_RunError (&progfuncs->funcs, "bad indexed global read in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPA->_int, current_progstate->globals_bytes>>2);
} }
ptr = ((eval_t *)&glob[OPA->_int]); ptr = ((eval_t *)&glob[OPA->_int]);
OPC->_int = ptr->_int; OPC->_int = ptr->_int;
break; break;
case OP_GLOAD_V: case OP_GLOAD_V:
errorif (OPA->_int < 0 || (OPA->_int+2)*4 >= current_progstate->globals_size) errorif (OPA->_int < 0 || OPA->_int >= (current_progstate->globals_bytes>>2)-2u)
{ {
prinst.pr_xstatement = st-pr_statements; prinst.pr_xstatement = st-pr_statements;
PR_RunError (&progfuncs->funcs, "bad indexed global read in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPA->_int, current_progstate->globals_size); PR_RunError (&progfuncs->funcs, "bad indexed global read in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPA->_int, current_progstate->globals_bytes>>2);
} }
ptr = ((eval_t *)&glob[OPA->_int]); ptr = ((eval_t *)&glob[OPA->_int]);
OPC->_vector[0] = ptr->_vector[0]; OPC->_vector[0] = ptr->_vector[0];
@ -1292,19 +1388,19 @@ reeval:
case OP_GSTOREP_FLD: case OP_GSTOREP_FLD:
case OP_GSTOREP_S: case OP_GSTOREP_S:
case OP_GSTOREP_FNC: case OP_GSTOREP_FNC:
errorif (OPB->_int < 0 || OPB->_int*4 >= current_progstate->globals_size) errorif (OPB->_int < 0 || OPB->_int >= (current_progstate->globals_bytes>>2))
{ {
prinst.pr_xstatement = st-pr_statements; prinst.pr_xstatement = st-pr_statements;
PR_RunError (&progfuncs->funcs, "bad indexed global write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPB->_int, (unsigned)prinst.addressableused); PR_RunError (&progfuncs->funcs, "bad indexed global write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPB->_int, current_progstate->globals_bytes>>2);
} }
ptr = ((eval_t *)&glob[OPB->_int]); ptr = ((eval_t *)&glob[OPB->_int]);
ptr->_int = OPA->_int; ptr->_int = OPA->_int;
break; break;
case OP_GSTOREP_V: case OP_GSTOREP_V:
errorif (OPB->_int < 0 || (OPB->_int+2)*4 >= current_progstate->globals_size) errorif (OPB->_int < 0 || OPB->_int >= (current_progstate->globals_bytes>>2)-2u)
{ {
prinst.pr_xstatement = st-pr_statements; prinst.pr_xstatement = st-pr_statements;
PR_RunError (&progfuncs->funcs, "bad indexed global write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPB->_int, (unsigned)prinst.addressableused); PR_RunError (&progfuncs->funcs, "bad indexed global write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPB->_int, current_progstate->globals_bytes>>2);
} }
ptr = ((eval_t *)&glob[OPB->_int]); ptr = ((eval_t *)&glob[OPB->_int]);
ptr->_vector[0] = OPA->_vector[0]; ptr->_vector[0] = OPA->_vector[0];

View File

@ -145,37 +145,37 @@ enum qcop_e {
OP_SUBSTOREP_F, //78 OP_SUBSTOREP_F, //78
OP_SUBSTOREP_V, //79 OP_SUBSTOREP_V, //79
OP_FETCH_GBL_F, //80 OP_FETCH_GBL_F, //80 has built-in bounds check
OP_FETCH_GBL_V, //81 OP_FETCH_GBL_V, //81 has built-in bounds check
OP_FETCH_GBL_S, //82 OP_FETCH_GBL_S, //82 has built-in bounds check
OP_FETCH_GBL_E, //83 OP_FETCH_GBL_E, //83 has built-in bounds check
OP_FETCH_GBL_FNC,//84 OP_FETCH_GBL_FNC,//84 has built-in bounds check
OP_CSTATE, //85 OP_CSTATE, //85
OP_CWSTATE, //86 OP_CWSTATE, //86
OP_THINKTIME, //87 OP_THINKTIME, //87 shortcut for OPA.nextthink=time+OPB
OP_BITSETSTORE_F, //88 redundant, for h2 compat OP_BITSETSTORE_F, //88 redundant, for h2 compat
OP_BITSETSTOREP_F, //89 OP_BITSETSTOREP_F, //89
OP_BITCLRSTORE_F, //90 OP_BITCLRSTORE_F, //90
OP_BITCLRSTOREP_F, //91 OP_BITCLRSTOREP_F, //91
OP_RAND0, //92 OP_RAND0, //92 OPC = random()
OP_RAND1, //93 OP_RAND1, //93 OPC = random()*OPA
OP_RAND2, //94 OP_RAND2, //94 OPC = random()*(OPB-OPA)+OPA
OP_RANDV0, //95 OP_RANDV0, //95 //3d/box versions of the above.
OP_RANDV1, //96 OP_RANDV1, //96
OP_RANDV2, //97 OP_RANDV2, //97
OP_SWITCH_F, //98 OP_SWITCH_F, //98 switchref=OPA; PC += OPB --- the jump allows the jump table (such as it is) to be inserted after the block.
OP_SWITCH_V, //99 OP_SWITCH_V, //99
OP_SWITCH_S, //100 OP_SWITCH_S, //100
OP_SWITCH_E, //101 OP_SWITCH_E, //101
OP_SWITCH_FNC, //102 OP_SWITCH_FNC, //102
OP_CASE, //103 OP_CASE, //103 if (OPA===switchref) PC += OPB
OP_CASERANGE, //104 OP_CASERANGE, //104 if (OPA<=switchref&&switchref<=OPB) PC += OPC
@ -184,9 +184,10 @@ enum qcop_e {
//the rest are added //the rest are added
//mostly they are various different ways of adding two vars with conversions. //mostly they are various different ways of adding two vars with conversions.
OP_CALL1H, //hexen2 calling convention (-TH2 requires us to remap OP_CALLX to these on load, -TFTE just uses these directly.)
OP_CALL2H, OP_CALL1H, //OFS_PARM0=OPB
OP_CALL3H, OP_CALL2H, //OFS_PARM0,1=OPB,OPC
OP_CALL3H, //no extra args
OP_CALL4H, OP_CALL4H,
OP_CALL5H, OP_CALL5H,
OP_CALL6H, //110 OP_CALL6H, //110
@ -195,21 +196,21 @@ enum qcop_e {
OP_STORE_I, OP_STORE_I,
OP_STORE_IF, OP_STORE_IF, //OPB.f = (float)OPA.i (makes more sense when written as a->b)
OP_STORE_FI, OP_STORE_FI, //OPB.i = (int)OPA.f
OP_ADD_I, OP_ADD_I,
OP_ADD_FI, OP_ADD_FI, //OPC.f = OPA.f + OPB.i
OP_ADD_IF, OP_ADD_IF, //OPC.f = OPA.i + OPB.f -- redundant...
OP_SUB_I, OP_SUB_I, //OPC.i = OPA.i - OPB.i
OP_SUB_FI, //120 OP_SUB_FI, //120 //OPC.f = OPA.f - OPB.i
OP_SUB_IF, OP_SUB_IF, //OPC.f = OPA.i - OPB.f
OP_CONV_ITOF, OP_CONV_ITOF, //OPC.f=(float)OPA.i
OP_CONV_FTOI, OP_CONV_FTOI, //OPC.i=(int)OPA.f
OP_CP_ITOF, OP_CP_ITOF, //OPC.f=(float)(*OPA).i
OP_CP_FTOI, OP_CP_FTOI, //OPC.i=(int)(*OPA).f
OP_LOAD_I, OP_LOAD_I,
OP_STOREP_I, OP_STOREP_I,
OP_STOREP_IF, OP_STOREP_IF,
@ -223,7 +224,7 @@ enum qcop_e {
OP_EQ_I, OP_EQ_I,
OP_NE_I, OP_NE_I,
OP_IFNOT_S, OP_IFNOT_S, //compares string empty, rather than just null.
OP_IF_S, OP_IF_S,
OP_NOT_I, OP_NOT_I,
@ -234,8 +235,8 @@ enum qcop_e {
OP_RSHIFT_I, OP_RSHIFT_I,
OP_LSHIFT_I, OP_LSHIFT_I,
OP_GLOBALADDRESS, OP_GLOBALADDRESS, //C.p = &A + B.i*4
OP_ADD_PIW, //add B words to A pointer OP_ADD_PIW, //C.p = A.p + B.i*4
OP_LOADA_F, OP_LOADA_F,
OP_LOADA_V, OP_LOADA_V,
@ -302,7 +303,7 @@ enum qcop_e {
OP_NE_IF, OP_NE_IF,
OP_NE_FI, OP_NE_FI,
//erm... FTEQCC doesn't make use of these... These are for DP. //erm... FTEQCC doesn't make use of these (doesn't model separate pointer types). These are for DP.
OP_GSTOREP_I, OP_GSTOREP_I,
OP_GSTOREP_F, OP_GSTOREP_F,
OP_GSTOREP_ENT, OP_GSTOREP_ENT,
@ -326,10 +327,16 @@ enum qcop_e {
OP_SWITCH_I,//hmm. OP_SWITCH_I,//hmm.
OP_GLOAD_V, OP_GLOAD_V,
//r3349+
OP_IF_F, OP_IF_F, //compares as an actual float, instead of treating -0 as positive.
OP_IFNOT_F, OP_IFNOT_F,
//r5697+
OP_STOREF_V, //3 elements...
OP_STOREF_F, //1 fpu element...
OP_STOREF_S, //1 string reference
OP_STOREF_I, //1 non-string reference/int
OP_NUMREALOPS, OP_NUMREALOPS,
/* /*

View File

@ -2097,8 +2097,8 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, void *ctx, void (PD
if (num == 0 && oldglobals) if (num == 0 && oldglobals)
{ {
if (pr_progstate[0].globals_size == oldglobalssize) if (pr_progstate[0].globals_bytes == oldglobalssize)
memcpy(pr_progstate[0].globals, oldglobals, pr_progstate[0].globals_size); memcpy(pr_progstate[0].globals, oldglobals, pr_progstate[0].globals_bytes);
free(oldglobals); free(oldglobals);
oldglobals = NULL; oldglobals = NULL;
} }
@ -2217,16 +2217,16 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, void *ctx, void (PD
if (oldglobals) if (oldglobals)
free(oldglobals); free(oldglobals);
oldglobals = NULL; oldglobals = NULL;
if (pr_progstate[0].globals_size) if (pr_progstate[0].globals_bytes)
{ {
oldglobals = malloc(pr_progstate[0].globals_size); oldglobals = malloc(pr_progstate[0].globals_bytes);
if (oldglobals) if (oldglobals)
{ {
oldglobalssize = pr_progstate[0].globals_size; oldglobalssize = pr_progstate[0].globals_bytes;
memcpy(oldglobals, pr_progstate[0].globals, oldglobalssize); memcpy(oldglobals, pr_progstate[0].globals, oldglobalssize);
} }
else else
externs->Printf("Unable to alloc %i bytes\n", pr_progstate[0].globals_size); externs->Printf("Unable to alloc %i bytes\n", pr_progstate[0].globals_bytes);
} }
PRAddressableFlush(progfuncs, 0); PRAddressableFlush(progfuncs, 0);
@ -2784,7 +2784,7 @@ retry:
current_progstate->statements = (void *)((qbyte *)pr_progs + pr_progs->ofs_statements); current_progstate->statements = (void *)((qbyte *)pr_progs + pr_progs->ofs_statements);
glob = pr_globals = (void *)((qbyte *)pr_progs + pr_progs->ofs_globals); glob = pr_globals = (void *)((qbyte *)pr_progs + pr_progs->ofs_globals);
current_progstate->globals_size = pr_progs->numglobals*sizeof(*pr_globals); current_progstate->globals_bytes = pr_progs->numglobals*sizeof(*pr_globals);
pr_linenums=NULL; pr_linenums=NULL;
pr_types=NULL; pr_types=NULL;

View File

@ -351,7 +351,7 @@ typedef struct progstate_s
// }; // };
// void *global_struct; // void *global_struct;
float *globals; // same as pr_global_struct float *globals; // same as pr_global_struct
int globals_size; // in bytes unsigned int globals_bytes; // in bytes
typeinfo_t *types; typeinfo_t *types;

View File

@ -655,12 +655,12 @@ QCC_opcode_t pr_opcodes[] =
{7, "<IF_F>", "IF_F", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void}, {7, "<IF_F>", "IF_F", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void},
{7, "<IFNOT_F>","IFNOT_F", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void}, {7, "<IFNOT_F>","IFNOT_F", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void},
/*
{7, "<=>", "STOREF_F", PC_STORE, ASSOC_RIGHT, &type_entity, &type_field, &type_float}, {7, "<=>", "STOREF_V", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_vector},
{7, "<=>", "STOREF_V", PC_STORE, ASSOC_RIGHT, &type_entity, &type_field, &type_vector}, {7, "<=>", "STOREF_F", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_float},
{7, "<=>", "STOREF_IF", PC_STORE, ASSOC_RIGHT, &type_entity, &type_field, &type_float}, {7, "<=>", "STOREF_S", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_string},
{7, "<=>", "STOREF_FI", PC_STORE, ASSOC_RIGHT, &type_entity, &type_field, &type_float}, {7, "<=>", "STOREF_I", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_integer},
*/
/* emulated ops begin here */ /* emulated ops begin here */
{7, "<>", "OP_EMULATED", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, {7, "<>", "OP_EMULATED", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float},
@ -775,8 +775,8 @@ static pbool OpAssignsToC(unsigned int op)
return false; return false;
if(op >= OP_SWITCH_F && op <= OP_CALL8H) if(op >= OP_SWITCH_F && op <= OP_CALL8H)
return false; return false;
if(op >= OP_RAND0 && op <= OP_RANDV2) // if(op >= OP_RAND0 && op <= OP_RANDV2)
return false; // return false;
// they use a and b, but have 3 types // they use a and b, but have 3 types
// safety // safety
if(op >= OP_BITSETSTORE_F && op <= OP_BITCLRSTOREP_F) if(op >= OP_BITSETSTORE_F && op <= OP_BITCLRSTOREP_F)
@ -791,6 +791,8 @@ static pbool OpAssignsToC(unsigned int op)
return false; //actually they do. return false; //actually they do.
if (op >= OP_STORE_I && op <= OP_STORE_FI) if (op >= OP_STORE_I && op <= OP_STORE_FI)
return false; return false;
if (op >= OP_STOREF_V && op <= OP_STOREF_I)
return false; //reads it, doesn't write.
if (op == OP_BOUNDCHECK || op == OP_UNUSED || op == OP_POP) if (op == OP_BOUNDCHECK || op == OP_UNUSED || op == OP_POP)
return false; return false;
return true; return true;
@ -847,6 +849,7 @@ static int OpAssignsCount(unsigned int op)
case OP_RANDV0: case OP_RANDV0:
case OP_RANDV1: case OP_RANDV1:
case OP_RANDV2: case OP_RANDV2:
return 1; //writes C, even when there's no A or B arg specified.
case OP_UNUSED: case OP_UNUSED:
case OP_POP: case OP_POP:
return 0; //FIXME return 0; //FIXME
@ -867,6 +870,11 @@ static int OpAssignsCount(unsigned int op)
case OP_CASE: case OP_CASE:
case OP_CASERANGE: case OP_CASERANGE:
return 0; return 0;
case OP_STOREF_V:
case OP_STOREF_F:
case OP_STOREF_S:
case OP_STOREF_I:
return 0; //stores to a.b rather than any direct value...
case OP_BOUNDCHECK: case OP_BOUNDCHECK:
return 0; return 0;
default: //the majority will write c default: //the majority will write c
@ -1182,6 +1190,8 @@ static pbool QCC_OPCodeValid(QCC_opcode_t *op)
case QCF_FTEH2: case QCF_FTEH2:
case QCF_FTE: case QCF_FTE:
case QCF_FTEDEBUG: case QCF_FTEDEBUG:
if (num >= OP_STOREF_V) //to be enabled at a later date - opcodes added in r5698.
return false;
return true; return true;
case QCF_DARKPLACES: case QCF_DARKPLACES:
//all id opcodes. //all id opcodes.
@ -4957,7 +4967,9 @@ static void QCC_VerifyArgs_setviewprop (const char *funcname, QCC_ref_t **arglis
{"VF_RT_DESTCOLOUR7", 219, ev_string, ev_float, ev_vector}, {"VF_RT_DESTCOLOUR7", 219, ev_string, ev_float, ev_vector},
{"VF_ENVMAP", 220, ev_string}, {"VF_ENVMAP", 220, ev_string},
{"VF_USERDATA", 221, ev_pointer, ev_integer}, {"VF_USERDATA", 221, ev_pointer, ev_integer},
{"VF_SKYROOM_CAMERA", 222, ev_vector} {"VF_SKYROOM_CAMERA", 222, ev_vector},
// {"VF_PIXELPSCALE", 223, ev_vector},
{"VF_PROJECTIONOFFSET", 224, ev_vector},
}; };
char temp[256]; char temp[256];
@ -5495,6 +5507,8 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func,
if (!strcmp(funcname, "strlen") && QCC_Intrinsic_strlen(&d, a)) if (!strcmp(funcname, "strlen") && QCC_Intrinsic_strlen(&d, a))
return d; return d;
if (!strcmp(funcname, "stof"))
return QCC_MakeFloatConst(atof(&strings[a->string]));
} }
} }
else if (opt_constantarithmatic && argcount == 2 && arglist[0]->type == REF_GLOBAL && arglist[1]->type == REF_GLOBAL) else if (opt_constantarithmatic && argcount == 2 && arglist[0]->type == REF_GLOBAL && arglist[1]->type == REF_GLOBAL)
@ -5503,16 +5517,23 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func,
const QCC_eval_t *b = QCC_SRef_EvalConst(arglist[1]->base); const QCC_eval_t *b = QCC_SRef_EvalConst(arglist[1]->base);
if (a && b) if (a && b)
{ {
if (!strcmp(funcname, "pow")) if (arglist[0]->cast == type_float && arglist[1]->cast == type_float)
return QCC_MakeFloatConst(pow(a->_float, b->_float));
if (!strcmp(funcname, "mod"))
return QCC_MakeFloatConst(fmodf((int)a->_float, (int)b->_float));
if (!strcmp(funcname, "bitshift"))
{ {
if (b->_float < 0) if (!strcmp(funcname, "pow"))
return QCC_MakeFloatConst((int)a->_float >> (int)-b->_float); return QCC_MakeFloatConst(pow(a->_float, b->_float));
else if (!strcmp(funcname, "mod"))
return QCC_MakeFloatConst((int)a->_float << (int)b->_float); return QCC_MakeFloatConst(fmodf((int)a->_float, (int)b->_float));
if (!strcmp(funcname, "min"))
return QCC_MakeFloatConst(min(a->_float, b->_float));
if (!strcmp(funcname, "max"))
return QCC_MakeFloatConst(max(a->_float, b->_float));
if (!strcmp(funcname, "bitshift"))
{
if (b->_float < 0)
return QCC_MakeFloatConst((int)a->_float >> (int)-b->_float);
else
return QCC_MakeFloatConst((int)a->_float << (int)b->_float);
}
} }
} }
} }
@ -5624,6 +5645,7 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func,
copyop_i = OP_LOADA_F; copyop_i = OP_LOADA_F;
copyop_idx = -1; copyop_idx = -1;
copyop_index = arglist[i]->index; copyop_index = arglist[i]->index;
copyop_index = QCC_SupplyConversion(copyop_index, ev_integer, true);
sref = arglist[i]->base; sref = arglist[i]->base;
} }
else if (arglist[i]->base.sym->arraylengthprefix && QCC_OPCodeValid(&pr_opcodes[OP_FETCH_GBL_F])) else if (arglist[i]->base.sym->arraylengthprefix && QCC_OPCodeValid(&pr_opcodes[OP_FETCH_GBL_F]))
@ -9690,15 +9712,53 @@ QCC_sref_t QCC_StoreSRefToRef(QCC_ref_t *dest, QCC_sref_t source, pbool readable
QCC_PR_ParseErrorPrintSRef(ERR_NOFUNC, dest->base, "Accessor has no set function"); QCC_PR_ParseErrorPrintSRef(ERR_NOFUNC, dest->base, "Accessor has no set function");
break; break;
case REF_FIELD: case REF_FIELD:
// { {
int storef_opcode;
//fixme: we should do this earlier, to preserve original instruction ordering. //fixme: we should do this earlier, to preserve original instruction ordering.
//such that self.enemy = (self = world); still has the same result (more common with function calls) //such that self.enemy = (self = world); still has the same result (more common with function calls)
dest = QCC_PR_BuildRef(&ptrref, REF_POINTER, if (dest->cast->type == ev_float)
QCC_PR_StatementFlags(&pr_opcodes[OP_ADDRESS], dest->base, dest->index, NULL, preservedest?STFL_PRESERVEA:0), //pointer address storef_opcode = OP_STOREF_F;
nullsref, (dest->index.cast->type == ev_field)?dest->index.cast->aux_type:type_variant, dest->readonly); else if (dest->cast->type == ev_vector)
preservedest = false; storef_opcode = OP_STOREF_V;
continue; else if (dest->cast->type == ev_string)
storef_opcode = OP_STOREF_S;
else if ( dest->cast->type == ev_entity ||
dest->cast->type == ev_field ||
dest->cast->type == ev_function ||
dest->cast->type == ev_pointer ||
dest->cast->type == ev_integer)
storef_opcode = OP_STOREF_I;
else
storef_opcode = OP_DONE;
//don't use it for arrays. address+storep_with_offset is less opcodes.
if (storef_opcode!=OP_DONE && dest->cast->size == 1 && QCC_OPCodeValid(&pr_opcodes[storef_opcode]))
{
dest->base.sym->referenced = true;
dest->index.sym->referenced = true;
source.sym->referenced = true;
//doesn't generate any temps.
QCC_PR_SimpleStatement(&pr_opcodes[storef_opcode], dest->base, dest->index, source, true);
if (!preservedest)
{
QCC_FreeTemp(dest->base);
QCC_FreeTemp(dest->index);
}
if (!readable)
{
QCC_FreeTemp(source);
source = nullsref;
}
}
else
{
dest = QCC_PR_BuildRef(&ptrref, REF_POINTER,
QCC_PR_StatementFlags(&pr_opcodes[OP_ADDRESS], dest->base, dest->index, NULL, preservedest?STFL_PRESERVEA:0), //pointer address
nullsref, (dest->index.cast->type == ev_field)?dest->index.cast->aux_type:type_variant, dest->readonly);
preservedest = false;
continue;
}
// source = QCC_StoreToRef( // source = QCC_StoreToRef(
// QCC_PR_BuildRef(&tmp, REF_POINTER, // QCC_PR_BuildRef(&tmp, REF_POINTER,
@ -9706,8 +9766,8 @@ QCC_sref_t QCC_StoreSRefToRef(QCC_ref_t *dest, QCC_sref_t source, pbool readable
// NULL, (dest->index->type->type == ev_field)?dest->index->type->aux_type:type_variant, dest->readonly), // NULL, (dest->index->type->type == ev_field)?dest->index->type->aux_type:type_variant, dest->readonly),
// source, readable, false); // source, readable, false);
// QCC_PR_ParseWarning(ERR_INTERNAL, "FIXME: trying to do references: assignments to ent.field not supported.\n"); // QCC_PR_ParseWarning(ERR_INTERNAL, "FIXME: trying to do references: assignments to ent.field not supported.\n");
// } }
// break; break;
} }
break; break;
} }
@ -12485,7 +12545,7 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_
return i; return i;
} }
} }
else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->a.ofs > 0) else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->a.ofs > 0 && !st->a.sym)
{ {
int jump = i + (int)st->a.ofs; int jump = i + (int)st->a.ofs;
ret = QCC_CheckOneUninitialised(i + 1, jump, def, min, max); ret = QCC_CheckOneUninitialised(i + 1, jump, def, min, max);
@ -12504,7 +12564,7 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_
return i; return i;
} }
} }
else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->b.ofs > 0 && !(st->flags & STF_LOGICOP)) else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->b.ofs > 0 && !st->b.sym && !(st->flags & STF_LOGICOP))
{ {
int jump = i + (int)st->b.ofs; int jump = i + (int)st->b.ofs;
//check if there's an else. //check if there's an else.
@ -12539,7 +12599,7 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_
return i; return i;
} }
else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->c.ofs > 0) else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->c.ofs > 0 && !st->c.sym)
{ {
int jump = i + (int)st->c.ofs; int jump = i + (int)st->c.ofs;
ret = QCC_CheckOneUninitialised(i + 1, jump, def, min, max); ret = QCC_CheckOneUninitialised(i + 1, jump, def, min, max);

View File

@ -1330,14 +1330,17 @@ static pbool QCC_PR_Precompiler(void)
else if (!QC_strcasecmp(qcc_token, "KK7")) else if (!QC_strcasecmp(qcc_token, "KK7"))
newtype = QCF_KK7; newtype = QCF_KK7;
else if (!QC_strcasecmp(qcc_token, "DP") || !QC_strcasecmp(qcc_token, "DARKPLACES")) else if (!QC_strcasecmp(qcc_token, "DP") || !QC_strcasecmp(qcc_token, "DARKPLACES"))
{
QCC_PR_ParseWarning(WARN_BADTARGET, "#pragma target \"%s\". Requires an unofficial patch to DP. Without that patch there is no support for any opcodes beyond vanilla.", qcc_token);
newtype = QCF_DARKPLACES; newtype = QCF_DARKPLACES;
}
else if (!QC_strcasecmp(qcc_token, "FTEDEBUG")) else if (!QC_strcasecmp(qcc_token, "FTEDEBUG"))
newtype = QCF_FTEDEBUG; newtype = QCF_FTEDEBUG;
else if (!QC_strcasecmp(qcc_token, "FTE")) else if (!QC_strcasecmp(qcc_token, "FTE"))
newtype = QCF_FTE; newtype = QCF_FTE;
else if (!QC_strcasecmp(qcc_token, "FTEH2")) else if (!QC_strcasecmp(qcc_token, "FTEH2"))
newtype = QCF_FTEH2; newtype = QCF_FTEH2;
else if (!QC_strcasecmp(qcc_token, "STANDARD") || !QC_strcasecmp(qcc_token, "ID")) else if (!QC_strcasecmp(qcc_token, "STANDARD") || !QC_strcasecmp(qcc_token, "ID") || !QC_strcasecmp(qcc_token, "VANILLA"))
newtype = QCF_STANDARD; newtype = QCF_STANDARD;
else if (!QC_strcasecmp(qcc_token, "DEBUG")) else if (!QC_strcasecmp(qcc_token, "DEBUG"))
newtype = QCF_FTEDEBUG; newtype = QCF_FTEDEBUG;

View File

@ -1200,6 +1200,18 @@ public:
return NULL;//"Type info not available. Compile first."; return NULL;//"Type info not available. Compile first.";
} }
void clearannotates(void)
{
for (int i = 0; i < numdocuments; i++)
{
document_s *d = docs[i];
s->setDocument(d->doc);
s->clearAnnotations();
}
if (curdoc)
s->setDocument(curdoc->doc);
}
bool annotate(const char *line) bool annotate(const char *line)
{ {
auto filename = line+6; auto filename = line+6;
@ -2292,6 +2304,8 @@ int GUIprintf(const char *msg, ...)
sizes.append(1); sizes.append(1);
mainwnd->logsplit.setSizes(sizes); mainwnd->logsplit.setSizes(sizes);
} }
mainwnd->docs.clearannotates();
return 0; return 0;
} }

View File

@ -119,7 +119,7 @@ int main (int argc, const char **argv)
{ {
unsigned int i; unsigned int i;
pbool sucess; pbool sucess;
#ifdef _WIN32 #if 0//def _WIN32
pbool writelog = true; //spew log files on windows. windows often closes the window as soon as the program ends making its output otherwise unreadable. pbool writelog = true; //spew log files on windows. windows often closes the window as soon as the program ends making its output otherwise unreadable.
#else #else
pbool writelog = false; //other systems are sane. pbool writelog = false; //other systems are sane.