-Fnoboundchecks is now -Fno-boundchecks (actually inverted behaviour with default-to-on) because -Fno-noboundchecks was stupid. bound checks are disabled when trying to compile xonotic (because xonotic is buggy and accesses arrays out of bounds).

fix logicops following vector types to shortcircuit properly.
fix ternary operators ending in field references - no longer ignores the result of the true pathway.
these two fixes appear to be sufficient to compile xonotic (note the array bounds issues that are abundant in xonotic, which will break with -TFTE and its direct array indexing, so be sure to re-enable bounds checks). The result probably isn't perfect, but it seems to work for me.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5162 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2017-11-04 04:01:33 +00:00
parent 9fc89eb03b
commit 39e124f72c
4 changed files with 59 additions and 24 deletions

View File

@ -825,15 +825,27 @@ reeval:
case OP_LOADA_ENT:
case OP_LOADA_S:
case OP_LOADA_FNC:
ptr = (eval_t *)(&OPA->_int + OPB->_int); /*pointer arithmatic*/
OPC->_int = ptr->_int;
i = st->a + OPB->_int;
if ((size_t)(i<<2) >= (size_t)current_progstate->globals_size)
{
QCFAULT(&progfuncs->funcs, "bad array read in %s (index %i)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int);
}
else
OPC->_int = ((eval_t *)&glob[i])->_int;
break;
case OP_LOADA_V:
ptr = (eval_t *)(&OPA->_int + OPB->_int);
OPC->_vector[0] = ptr->_vector[0];
OPC->_vector[1] = ptr->_vector[1];
OPC->_vector[2] = ptr->_vector[2];
i = st->a + OPB->_int;
if ((size_t)(i<<2) >= (size_t)current_progstate->globals_size)
{
QCFAULT(&progfuncs->funcs, "bad array read in %s (index %i)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int);
}
else
{
OPC->_vector[0] = ((eval_t *)&glob[i])->_vector[0];
OPC->_vector[1] = ((eval_t *)&glob[i])->_vector[1];
OPC->_vector[2] = ((eval_t *)&glob[i])->_vector[2];
}
break;

View File

@ -619,7 +619,7 @@ extern pbool flag_msvcstyle;
extern pbool flag_debugmacros;
extern pbool flag_filetimes;
extern pbool flag_typeexplicit;
extern pbool flag_noboundchecks;
extern pbool flag_boundchecks;
extern pbool flag_brokenarrays;
extern pbool flag_rootconstructor;
extern pbool flag_guiannotate;

View File

@ -116,7 +116,7 @@ pbool flag_debugmacros; //Print out #defines as they are expanded, for debuggin
pbool flag_assume_integer; //5 - is that an integer or a float? qcc says float. but we support int too, so maybe we want that instead?
pbool flag_filetimes;
pbool flag_typeexplicit; //no implicit type conversions, you must do the casts yourself.
pbool flag_noboundchecks; //Disable generation of bound check instructions.
pbool flag_boundchecks; //Disable generation of bound check instructions.
pbool flag_guiannotate;
pbool flag_brokenarrays; //return array; returns array[0] instead of &array;
pbool flag_rootconstructor; //if true, class constructors are ordered to call the super constructor first, rather than the child constructor
@ -7025,7 +7025,7 @@ vectorarrayindex:
if (i < 0 || i >= 3)
QCC_PR_ParseErrorPrintSRef(0, r->base, "(vector) array index out of bounds");
}
else if (QCC_OPCodeValid(&pr_opcodes[OP_BOUNDCHECK]) && !flag_noboundchecks)
else if (QCC_OPCodeValid(&pr_opcodes[OP_BOUNDCHECK]) && flag_boundchecks)
{
tmp = QCC_SupplyConversion(tmp, ev_integer, true);
QCC_PR_SimpleStatement (&pr_opcodes[OP_BOUNDCHECK], tmp, QCC_MakeSRef(NULL, 3, NULL), nullsref, false);
@ -7047,7 +7047,7 @@ vectorarrayindex:
if (i < 0 || i >= 3)
QCC_PR_ParseErrorPrintSRef(0, r->base, "(vector) array index out of bounds");
}
else if (QCC_OPCodeValid(&pr_opcodes[OP_BOUNDCHECK]) && !flag_noboundchecks)
else if (QCC_OPCodeValid(&pr_opcodes[OP_BOUNDCHECK]) && flag_boundchecks)
{
tmp = QCC_SupplyConversion(tmp, ev_integer, true);
QCC_PR_SimpleStatement (&pr_opcodes[OP_BOUNDCHECK], tmp, QCC_MakeSRef(NULL, 3, NULL), nullsref, false);
@ -7072,7 +7072,7 @@ vectorarrayindex:
}
else
{
if (QCC_OPCodeValid(&pr_opcodes[OP_BOUNDCHECK]) && !flag_noboundchecks)
if (QCC_OPCodeValid(&pr_opcodes[OP_BOUNDCHECK]) && flag_boundchecks)
{
tmp = QCC_SupplyConversion(tmp, ev_integer, true);
QCC_PR_SimpleStatement (&pr_opcodes[OP_BOUNDCHECK], tmp, QCC_MakeSRef(NULL, arraysize, NULL), nullsref, false);
@ -8634,7 +8634,7 @@ QCC_sref_t QCC_LoadFromArray(QCC_sref_t base, QCC_sref_t index, QCC_type_t *t, p
base.sym->referenced = true;
if (base.cast->type == ev_field && base.sym->constant && !base.sym->initialized && flag_noboundchecks && flag_fasttrackarrays)
if (base.cast->type == ev_field && base.sym->constant && !base.sym->initialized && !flag_boundchecks && flag_fasttrackarrays)
{
int i;
//denormalised floats means we could do:
@ -8649,9 +8649,13 @@ QCC_sref_t QCC_LoadFromArray(QCC_sref_t base, QCC_sref_t index, QCC_type_t *t, p
//its contiguous. we'll do this in two instructions.
if (i == base.sym->arraysize)
{
//denormalised floats means we could do:
//return (add_f: base + (mul_f: index*1i))
return QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_F], base, QCC_PR_StatementFlags(&pr_opcodes[OP_MUL_F], index, QCC_MakeIntConst(1), NULL, 0), NULL, 0);
if (QCC_OPCodeValid(&pr_opcodes[OP_ADD_I]))
return QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_I], base, index, NULL, 0);
else
{
QCC_PR_ParseWarning(WARN_DENORMAL, "using denormals to accelerate field-array access");
return QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_F], base, QCC_PR_StatementFlags(&pr_opcodes[OP_MUL_F], index, QCC_MakeIntConst(1), NULL, 0), NULL, 0);
}
}
}
@ -9320,7 +9324,12 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags)
//r=a?:b -> if (a) r=a else r=b;
fromj = QCC_Generate_OP_IFNOT(val, true);
lvalisnull = QCC_SRef_IsNull(val);
#if 1
//hack: make local, not temp. this disables assignment/temp folding...
r = QCC_MakeSRefForce(QCC_PR_DummyDef(r.cast=val.cast, "ternary", pr_scope, 0, NULL, 0, true, GDF_STRIP), 0, val.cast);
#else
r = QCC_GetTemp(val.cast);
#endif
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[(r.cast->size>=3)?OP_STORE_V:OP_STORE_F], val, r, &truthstore, STFL_PRESERVEB));
}
else
@ -9350,7 +9359,12 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags)
if (val.cast->type == ev_integer && !QCC_OPCodeValid(&pr_opcodes[OP_STORE_I]))
val = QCC_SupplyConversion(val, ev_float, true);
lvalisnull = QCC_SRef_IsNull(val);
#if 1
//hack: make local, not temp. this disables assignment/temp folding...
r = QCC_MakeSRefForce(QCC_PR_DummyDef(r.cast=val.cast, "ternary", pr_scope, 0, NULL, 0, true, GDF_STRIP), 0, val.cast);
#else
r = QCC_GetTemp(val.cast);
#endif
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[(r.cast->size>=3)?OP_STORE_V:OP_STORE_F], val, r, &truthstore, STFL_PRESERVEB));
//r can be stomped upon until its reused anyway
@ -9624,12 +9638,20 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags)
logicjump = NULL;
lhsd = QCC_RefToDef(lhsr, true);
if (opt_logicops && lhsd.cast->size == 1)
if (opt_logicops && (lhsd.cast->size == 1 || lhsd.cast->type == ev_vector))
{
if (!strcmp(op->name, "&&")) //guarenteed to be false if the lhs is false
{
if (lhsd.cast->type == ev_vector)
lhsd = QCC_PR_StatementFlags (&pr_opcodes[OP_MUL_V], lhsd, lhsd, NULL, STFL_PRESERVEA);
logicjump = QCC_Generate_OP_IFNOT(lhsd, true);
}
else if (!strcmp(op->name, "||")) //guarenteed to be true if the lhs is true
{
if (lhsd.cast->type == ev_vector)
lhsd = QCC_PR_StatementFlags (&pr_opcodes[OP_MUL_V], lhsd, lhsd, NULL, STFL_PRESERVEA);
logicjump = QCC_Generate_OP_IF(lhsd, true);
}
}
rhsr = QCC_PR_RefExpression (&rhsbuf, priority-1, exprflags | EXPR_DISALLOW_ARRAYASSIGN);
@ -12845,7 +12867,7 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, QCC_def_t *arraydef, char *ar
}
*/
if (!flag_noboundchecks)
if (flag_boundchecks)
QCC_FreeTemp(QCC_PR_Statement(pr_opcodes+OP_IF_I, QCC_PR_StatementFlags(pr_opcodes+OP_LT_F, index, QCC_MakeFloatConst(0), NULL, STFL_PRESERVEA), nullsref, &bc1));
if (vectortrick.cast)
@ -12856,7 +12878,7 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, QCC_def_t *arraydef, char *ar
//we need to work out which part, x/y/z that it's stored in.
//0,1,2 = i - ((int)i/3 *) 3;
if (!flag_noboundchecks)
if (flag_boundchecks)
QCC_FreeTemp(QCC_PR_Statement(pr_opcodes+OP_IF_I, QCC_PR_StatementFlags(pr_opcodes+OP_GE_F, index, QCC_MakeFloatConst(numslots), NULL, STFL_PRESERVEA), nullsref, &bc2));
div3 = QCC_PR_GetSRef(type_float, "div3___", pr_scope, true, 0, false);
@ -13026,7 +13048,7 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, QCC_def_t *arraydef, char *ar
//note that the array size is coded into the globals, one index before the array.
QCC_PR_SimpleStatement(&pr_opcodes[OP_CONV_FTOI], index, nullsref, index, true); //address stuff is integer based, but standard qc (which this accelerates in supported engines) only supports floats
if (!flag_noboundchecks)
if (flag_boundchecks)
QCC_PR_SimpleStatement (&pr_opcodes[OP_BOUNDCHECK], index, QCC_MakeSRef(NULL, numslots, NULL), nullsref, true);//annoy the programmer. :p
if (thearray.cast->type == ev_vector)//shift it upwards for larger types
QCC_PR_SimpleStatement(&pr_opcodes[OP_MUL_I], index, QCC_MakeIntConst(thearray.cast->size), index, true);
@ -13041,9 +13063,9 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, QCC_def_t *arraydef, char *ar
st->b.ofs = &statements[numstatements] - st;
}
if (!flag_noboundchecks)
if (flag_boundchecks)
QCC_FreeTemp(QCC_PR_Statement(pr_opcodes+OP_IF_I, QCC_PR_StatementFlags(pr_opcodes+OP_LT_F, index, QCC_MakeFloatConst(0), NULL, STFL_PRESERVEA), nullsref, &bc1));
if (!flag_noboundchecks)
if (flag_boundchecks)
QCC_FreeTemp(QCC_PR_Statement(pr_opcodes+OP_IF_I, QCC_PR_StatementFlags(pr_opcodes+OP_GE_F, index, QCC_MakeFloatConst(numslots), NULL, STFL_PRESERVEA), nullsref, &bc2));
QCC_PR_ArraySetRecurseDivide(thearray, index, value, 0, numslots);

View File

@ -375,7 +375,7 @@ compiler_flag_t compiler_flag[] = {
{&pr_subscopedlocals, FLAG_MIDCOMPILE,"subscope", "Subscoped Locals", "Restrict the scope of locals to the block they are actually defined within, as in C."},
{&verbose, FLAG_MIDCOMPILE,"verbose", "Verbose", "Lots of extra compiler messages."},
{&flag_typeexplicit, FLAG_MIDCOMPILE,"typeexplicit", "Explicit types", "All type conversions must be explicit or directly supported by instruction set."},
{&flag_noboundchecks, FLAG_MIDCOMPILE,"noboundchecks","Disable Bound Checks", "Disable array index checks, speeding up array access but can result in your code misbehaving."},
{&flag_boundchecks, defaultflag, "boundchecks","Disable Bound Checks", "Disable array index checks, speeding up array access but can result in your code misbehaving."},
{&flag_attributes, hideflag, "attributes", "[[attributes]]", "WARNING: This syntax conflicts with vector constructors."},
{&flag_assumevar, hideflag, "assumevar", "explicit consts", "Initialised globals will be considered non-const by default."},
{&flag_dblstarexp, hideflag, "ssp", "** exponent", "Treat ** as an operator for exponents, instead of multiplying by a dereferenced pointer."},
@ -1478,14 +1478,14 @@ pbool QCC_WriteData (int crc)
if (qcc_targetformat == QCF_DARKPLACES)
printf("DarkPlaces or FTE will be required\n");
else
printf("An FTE executor will be required\n");
printf("FTE's QCLib will be required\n");
}
break;
case QCF_KK7:
if (bodylessfuncs)
printf("Warning: There are some functions without bodies.\n");
if (numpr_globals > 65530)
printf("Warning: Saving is not supported. Ensure all engine read fields and globals are defined early on.\n");
printf("Warning: Saving is not fully supported. Ensure all engine read fields and globals are defined early on.\n");
printf("A KK compatible executor will be required (FTE/KK)\n");
outputsttype = PST_KKQWSV;
@ -4151,6 +4151,7 @@ void QCC_PR_CommandLinePrecompilerOptions (void)
{
flag_ifvector = flag_vectorlogic = true;
flag_dblstarexp = flag_attributes = flag_assumevar = pr_subscopedlocals = flag_cpriority = flag_allowuninit = true;
flag_boundchecks = false; //gmqcc doesn't support these, so xonotic is buggy shite.
opt_logicops = true;
qccwarningaction[WARN_CONSTANTCOMPARISON] = WA_IGNORE;
qccwarningaction[WARN_POINTLESSSTATEMENT] = WA_IGNORE;