From 62a4572f2340242a55310d844366892dee906b75 Mon Sep 17 00:00:00 2001 From: Spoike Date: Sat, 30 May 2020 12:12:46 +0000 Subject: [PATCH] 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 --- engine/qclib/execloop.h | 116 +++++++++++++++++++++++++++++++---- engine/qclib/pr_comp.h | 73 ++++++++++++---------- engine/qclib/pr_edict.c | 14 ++--- engine/qclib/progsint.h | 2 +- engine/qclib/qcc_pr_comp.c | 120 +++++++++++++++++++++++++++---------- engine/qclib/qcc_pr_lex.c | 5 +- engine/qclib/qccguiqt.cpp | 14 +++++ engine/qclib/qcctui.c | 2 +- 8 files changed, 263 insertions(+), 83 deletions(-) diff --git a/engine/qclib/execloop.h b/engine/qclib/execloop.h index f83534c05..a993a7740 100644 --- a/engine/qclib/execloop.h +++ b/engine/qclib/execloop.h @@ -422,6 +422,102 @@ reeval: *(unsigned char *)ptr = (char)OPA->_float; 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 case OP_ADDRESS: errorif ((unsigned)OPA->edict >= (unsigned)num_edicts) @@ -828,7 +924,7 @@ reeval: case OP_LOADA_S: case OP_LOADA_FNC: 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); } @@ -838,7 +934,7 @@ reeval: case OP_LOADA_V: 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); } @@ -1267,19 +1363,19 @@ reeval: case OP_GLOAD_ENT: case OP_GLOAD_S: 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; - 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]); OPC->_int = ptr->_int; break; 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; - 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]); OPC->_vector[0] = ptr->_vector[0]; @@ -1292,19 +1388,19 @@ reeval: case OP_GSTOREP_FLD: case OP_GSTOREP_S: 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; - 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->_int = OPA->_int; break; 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; - 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->_vector[0] = OPA->_vector[0]; diff --git a/engine/qclib/pr_comp.h b/engine/qclib/pr_comp.h index 12d1f1bdc..a20ee8061 100644 --- a/engine/qclib/pr_comp.h +++ b/engine/qclib/pr_comp.h @@ -145,37 +145,37 @@ enum qcop_e { OP_SUBSTOREP_F, //78 OP_SUBSTOREP_V, //79 - OP_FETCH_GBL_F, //80 - OP_FETCH_GBL_V, //81 - OP_FETCH_GBL_S, //82 - OP_FETCH_GBL_E, //83 - OP_FETCH_GBL_FNC,//84 + OP_FETCH_GBL_F, //80 has built-in bounds check + OP_FETCH_GBL_V, //81 has built-in bounds check + OP_FETCH_GBL_S, //82 has built-in bounds check + OP_FETCH_GBL_E, //83 has built-in bounds check + OP_FETCH_GBL_FNC,//84 has built-in bounds check OP_CSTATE, //85 OP_CWSTATE, //86 - OP_THINKTIME, //87 + OP_THINKTIME, //87 shortcut for OPA.nextthink=time+OPB OP_BITSETSTORE_F, //88 redundant, for h2 compat OP_BITSETSTOREP_F, //89 OP_BITCLRSTORE_F, //90 OP_BITCLRSTOREP_F, //91 - OP_RAND0, //92 - OP_RAND1, //93 - OP_RAND2, //94 - OP_RANDV0, //95 + OP_RAND0, //92 OPC = random() + OP_RAND1, //93 OPC = random()*OPA + OP_RAND2, //94 OPC = random()*(OPB-OPA)+OPA + OP_RANDV0, //95 //3d/box versions of the above. OP_RANDV1, //96 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_S, //100 OP_SWITCH_E, //101 OP_SWITCH_FNC, //102 - OP_CASE, //103 - OP_CASERANGE, //104 + OP_CASE, //103 if (OPA===switchref) PC += OPB + OP_CASERANGE, //104 if (OPA<=switchref&&switchref<=OPB) PC += OPC @@ -184,9 +184,10 @@ enum qcop_e { //the rest are added //mostly they are various different ways of adding two vars with conversions. - OP_CALL1H, - OP_CALL2H, - OP_CALL3H, + //hexen2 calling convention (-TH2 requires us to remap OP_CALLX to these on load, -TFTE just uses these directly.) + OP_CALL1H, //OFS_PARM0=OPB + OP_CALL2H, //OFS_PARM0,1=OPB,OPC + OP_CALL3H, //no extra args OP_CALL4H, OP_CALL5H, OP_CALL6H, //110 @@ -195,21 +196,21 @@ enum qcop_e { OP_STORE_I, - OP_STORE_IF, - OP_STORE_FI, + OP_STORE_IF, //OPB.f = (float)OPA.i (makes more sense when written as a->b) + OP_STORE_FI, //OPB.i = (int)OPA.f OP_ADD_I, - OP_ADD_FI, - OP_ADD_IF, + OP_ADD_FI, //OPC.f = OPA.f + OPB.i + OP_ADD_IF, //OPC.f = OPA.i + OPB.f -- redundant... - OP_SUB_I, - OP_SUB_FI, //120 - OP_SUB_IF, + OP_SUB_I, //OPC.i = OPA.i - OPB.i + OP_SUB_FI, //120 //OPC.f = OPA.f - OPB.i + OP_SUB_IF, //OPC.f = OPA.i - OPB.f - OP_CONV_ITOF, - OP_CONV_FTOI, - OP_CP_ITOF, - OP_CP_FTOI, + OP_CONV_ITOF, //OPC.f=(float)OPA.i + OP_CONV_FTOI, //OPC.i=(int)OPA.f + OP_CP_ITOF, //OPC.f=(float)(*OPA).i + OP_CP_FTOI, //OPC.i=(int)(*OPA).f OP_LOAD_I, OP_STOREP_I, OP_STOREP_IF, @@ -223,7 +224,7 @@ enum qcop_e { OP_EQ_I, OP_NE_I, - OP_IFNOT_S, + OP_IFNOT_S, //compares string empty, rather than just null. OP_IF_S, OP_NOT_I, @@ -234,8 +235,8 @@ enum qcop_e { OP_RSHIFT_I, OP_LSHIFT_I, - OP_GLOBALADDRESS, - OP_ADD_PIW, //add B words to A pointer + OP_GLOBALADDRESS, //C.p = &A + B.i*4 + OP_ADD_PIW, //C.p = A.p + B.i*4 OP_LOADA_F, OP_LOADA_V, @@ -302,7 +303,7 @@ enum qcop_e { OP_NE_IF, 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_F, OP_GSTOREP_ENT, @@ -326,10 +327,16 @@ enum qcop_e { OP_SWITCH_I,//hmm. OP_GLOAD_V, - - OP_IF_F, +//r3349+ + OP_IF_F, //compares as an actual float, instead of treating -0 as positive. 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, /* diff --git a/engine/qclib/pr_edict.c b/engine/qclib/pr_edict.c index e0b1498d4..4119af56f 100644 --- a/engine/qclib/pr_edict.c +++ b/engine/qclib/pr_edict.c @@ -2097,8 +2097,8 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, void *ctx, void (PD if (num == 0 && oldglobals) { - if (pr_progstate[0].globals_size == oldglobalssize) - memcpy(pr_progstate[0].globals, oldglobals, pr_progstate[0].globals_size); + if (pr_progstate[0].globals_bytes == oldglobalssize) + memcpy(pr_progstate[0].globals, oldglobals, pr_progstate[0].globals_bytes); free(oldglobals); oldglobals = NULL; } @@ -2217,16 +2217,16 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, void *ctx, void (PD if (oldglobals) free(oldglobals); 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) { - oldglobalssize = pr_progstate[0].globals_size; + oldglobalssize = pr_progstate[0].globals_bytes; memcpy(oldglobals, pr_progstate[0].globals, oldglobalssize); } 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); @@ -2784,7 +2784,7 @@ retry: current_progstate->statements = (void *)((qbyte *)pr_progs + pr_progs->ofs_statements); 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_types=NULL; diff --git a/engine/qclib/progsint.h b/engine/qclib/progsint.h index c217642e1..1431ed6a0 100644 --- a/engine/qclib/progsint.h +++ b/engine/qclib/progsint.h @@ -351,7 +351,7 @@ typedef struct progstate_s // }; // void *global_struct; float *globals; // same as pr_global_struct - int globals_size; // in bytes + unsigned int globals_bytes; // in bytes typeinfo_t *types; diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index a00ed9134..c87abcd78 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -655,12 +655,12 @@ QCC_opcode_t pr_opcodes[] = {7, "", "IF_F", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void}, {7, "","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_STORE, ASSOC_RIGHT, &type_entity, &type_field, &type_vector}, -{7, "<=>", "STOREF_IF", PC_STORE, ASSOC_RIGHT, &type_entity, &type_field, &type_float}, -{7, "<=>", "STOREF_FI", 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_F", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_float}, +{7, "<=>", "STOREF_S", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_string}, +{7, "<=>", "STOREF_I", PC_NONE, ASSOC_RIGHT, &type_entity, &type_field, &type_integer}, + /* emulated ops begin here */ {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; if(op >= OP_SWITCH_F && op <= OP_CALL8H) return false; - if(op >= OP_RAND0 && op <= OP_RANDV2) - return false; +// if(op >= OP_RAND0 && op <= OP_RANDV2) +// return false; // they use a and b, but have 3 types // safety if(op >= OP_BITSETSTORE_F && op <= OP_BITCLRSTOREP_F) @@ -791,6 +791,8 @@ static pbool OpAssignsToC(unsigned int op) return false; //actually they do. if (op >= OP_STORE_I && op <= OP_STORE_FI) 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) return false; return true; @@ -847,6 +849,7 @@ static int OpAssignsCount(unsigned int op) case OP_RANDV0: case OP_RANDV1: case OP_RANDV2: + return 1; //writes C, even when there's no A or B arg specified. case OP_UNUSED: case OP_POP: return 0; //FIXME @@ -867,6 +870,11 @@ static int OpAssignsCount(unsigned int op) case OP_CASE: case OP_CASERANGE: 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: return 0; default: //the majority will write c @@ -1182,6 +1190,8 @@ static pbool QCC_OPCodeValid(QCC_opcode_t *op) case QCF_FTEH2: case QCF_FTE: case QCF_FTEDEBUG: + if (num >= OP_STOREF_V) //to be enabled at a later date - opcodes added in r5698. + return false; return true; case QCF_DARKPLACES: //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_ENVMAP", 220, ev_string}, {"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]; @@ -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)) 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) @@ -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); if (a && b) { - if (!strcmp(funcname, "pow")) - 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 (arglist[0]->cast == type_float && arglist[1]->cast == type_float) { - if (b->_float < 0) - return QCC_MakeFloatConst((int)a->_float >> (int)-b->_float); - else - return QCC_MakeFloatConst((int)a->_float << (int)b->_float); + if (!strcmp(funcname, "pow")) + 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, "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_idx = -1; copyop_index = arglist[i]->index; + copyop_index = QCC_SupplyConversion(copyop_index, ev_integer, true); sref = arglist[i]->base; } 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"); break; case REF_FIELD: -// { + { + int storef_opcode; //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) - - 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; + + if (dest->cast->type == ev_float) + storef_opcode = OP_STOREF_F; + else if (dest->cast->type == ev_vector) + storef_opcode = OP_STOREF_V; + 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( // 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), // source, readable, false); // QCC_PR_ParseWarning(ERR_INTERNAL, "FIXME: trying to do references: assignments to ent.field not supported.\n"); -// } -// break; + } + break; } break; } @@ -12485,7 +12545,7 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_ 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; ret = QCC_CheckOneUninitialised(i + 1, jump, def, min, max); @@ -12504,7 +12564,7 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_ 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; //check if there's an else. @@ -12539,7 +12599,7 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_ 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; ret = QCC_CheckOneUninitialised(i + 1, jump, def, min, max); diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index f1bb507f0..eaca50cc0 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -1330,14 +1330,17 @@ static pbool QCC_PR_Precompiler(void) else if (!QC_strcasecmp(qcc_token, "KK7")) newtype = QCF_KK7; 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; + } else if (!QC_strcasecmp(qcc_token, "FTEDEBUG")) newtype = QCF_FTEDEBUG; else if (!QC_strcasecmp(qcc_token, "FTE")) newtype = QCF_FTE; else if (!QC_strcasecmp(qcc_token, "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; else if (!QC_strcasecmp(qcc_token, "DEBUG")) newtype = QCF_FTEDEBUG; diff --git a/engine/qclib/qccguiqt.cpp b/engine/qclib/qccguiqt.cpp index d1cf81169..b376673c7 100644 --- a/engine/qclib/qccguiqt.cpp +++ b/engine/qclib/qccguiqt.cpp @@ -1200,6 +1200,18 @@ public: 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) { auto filename = line+6; @@ -2292,6 +2304,8 @@ int GUIprintf(const char *msg, ...) sizes.append(1); mainwnd->logsplit.setSizes(sizes); } + + mainwnd->docs.clearannotates(); return 0; } diff --git a/engine/qclib/qcctui.c b/engine/qclib/qcctui.c index a2772ca31..f6bc7bcb8 100644 --- a/engine/qclib/qcctui.c +++ b/engine/qclib/qcctui.c @@ -119,7 +119,7 @@ int main (int argc, const char **argv) { unsigned int i; 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. #else pbool writelog = false; //other systems are sane.