Add support for generating DP-style arrays, now that it looks like they might actually be getting support in DP...

Update list of opcodes usable with -Tdp
Fix issue with logic ops resulting in crashes.
Fix enumflags crashes.



git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5726 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2020-07-13 17:48:16 +00:00
parent 3129400101
commit 474aaf68a2
6 changed files with 833 additions and 332 deletions

View file

@ -879,7 +879,7 @@ reeval:
OPC->_int = (int)OPA->_float;
break;
case OP_CP_ITOF:
case OP_LOADP_ITOF:
i = OPA->_int;
errorif (QCPOINTERREADFAIL(i, sizeof(char)))
{
@ -889,7 +889,7 @@ reeval:
OPC->_float = (float)ptr->_int;
break;
case OP_CP_FTOI:
case OP_LOADP_FTOI:
i = OPA->_int;
errorif (QCPOINTERREADFAIL(i, sizeof(char)))
{

View file

@ -208,10 +208,10 @@ enum qcop_e {
OP_SUB_FI, //120 //OPC.f = OPA.f - OPB.i
OP_SUB_IF, //OPC.f = OPA.i - OPB.f
OP_CONV_ITOF, //OPC.f=(float)OPA.i
OP_CONV_ITOF, //OPC.f=(float)OPA.i -- useful mostly so decompilers don't do weird stuff.
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_LOADP_ITOF, //OPC.f=(float)(*OPA).i -- fixme: rename to LOADP_ITOF
OP_LOADP_FTOI, //OPC.i=(int)(*OPA).f
OP_LOAD_I,
OP_STOREP_I,
OP_STOREP_IF,
@ -304,7 +304,7 @@ enum qcop_e {
OP_NE_IF,
OP_NE_FI,
//erm... FTEQCC doesn't make use of these (doesn't model separate pointer types). These are for DP.
//fte doesn't really model two separate pointer types. these are thus special-case things for array access only.
OP_GSTOREP_I,
OP_GSTOREP_F,
OP_GSTOREP_ENT,
@ -312,7 +312,7 @@ enum qcop_e {
OP_GSTOREP_S,
OP_GSTOREP_FNC,
OP_GSTOREP_V,
OP_GADDRESS,
OP_GADDRESS, //poorly defined opcode, which makes it too unreliable to actually use.
OP_GLOAD_I,
OP_GLOAD_F,
OP_GLOAD_FLD,

View file

@ -84,9 +84,11 @@ extern int MAX_CONSTANTS;
#define MAXCONSTANTPARAMLENGTH 32
#define MAXCONSTANTPARAMS 32
typedef enum {QCF_STANDARD, QCF_HEXEN2, QCF_UHEXEN2, QCF_DARKPLACES, QCF_FTE, QCF_FTEDEBUG, QCF_FTEH2, QCF_KK7, QCF_QTEST} qcc_targetformat_t;
typedef enum {QCF_STANDARD, QCF_HEXEN2, QCF_UHEXEN2, QCF_DARKPLACES, QCF_QSS, QCF_FTE, QCF_FTEDEBUG, QCF_FTEH2, QCF_KK7, QCF_QTEST} qcc_targetformat_t;
extern qcc_targetformat_t qcc_targetformat;
void QCC_OPCodeSetTarget(qcc_targetformat_t targfmt);
extern unsigned int qcc_targetversion;
void QCC_OPCodeSetTarget(qcc_targetformat_t targfmt, unsigned int targver);
pbool QCC_OPCodeSetTargetName(const char *targ);
/*
@ -401,12 +403,14 @@ typedef struct QCC_def_s
char *comment; //ui info
struct QCC_def_s *next;
struct QCC_def_s *nextlocal; //provides a chain of local variables for the opt_locals_marshalling optimisation.
gofs_t ofs;
gofs_t ofs; //offset of symbol relative to symbol header.
struct QCC_function_s *scope; // function the var was defined in, or NULL
struct QCC_def_s *deftail; // arrays and structs create multiple globaldef objects providing different types at the different parts of the single object (struct), or alternative names (vectors). this allows us to correctly set the const type based upon how its initialised.
struct QCC_def_s *generatedfor;
int constant; // 1 says we can use the value over and over again. 2 is used on fields, for some reason.
struct QCC_def_s *reloc; //the symbol that we're a reloc for
struct QCC_def_s *gaddress; //a def that holds our offset.
struct QCC_def_s *symbolheader; //this is the original symbol within which the def is stored.
union QCC_eval_s *symboldata; //null if uninitialised. use sym->symboldata[sym->ofs] to index.
unsigned int symbolsize; //total byte size of symbol
@ -583,6 +587,7 @@ extern pbool keyword_asm;
extern pbool keyword_break;
extern pbool keyword_case;
extern pbool keyword_class;
extern pbool keyword_accessor;
extern pbool keyword_const;
extern pbool keyword_inout;
extern pbool keyword_optional;

File diff suppressed because it is too large Load diff

View file

@ -1323,43 +1323,9 @@ static pbool QCC_PR_Precompiler(void)
}
else if (!QC_strcasecmp(qcc_token, "TARGET"))
{
int newtype = qcc_targetformat;
QCC_COM_Parse(msg);
if (!QC_strcasecmp(qcc_token, "H2") || !QC_strcasecmp(qcc_token, "HEXEN2"))
newtype = QCF_HEXEN2;
else if (!QC_strcasecmp(qcc_token, "UHEXEN2"))
newtype = QCF_UHEXEN2;
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") || !QC_strcasecmp(qcc_token, "VANILLA"))
newtype = QCF_STANDARD;
else if (!QC_strcasecmp(qcc_token, "DEBUG"))
newtype = QCF_FTEDEBUG;
else if (!QC_strcasecmp(qcc_token, "QTEST"))
newtype = QCF_QTEST;
else
if (!QCC_OPCodeSetTargetName(qcc_token))
QCC_PR_ParseWarning(WARN_BADTARGET, "Unknown target \'%s\'. Ignored.\nValid targets are: ID, HEXEN2, FTE, FTEH2, KK7, DP(patched)", qcc_token);
if (numstatements > 1)
{
if ((qcc_targetformat == QCF_HEXEN2 || qcc_targetformat == QCF_UHEXEN2 || qcc_targetformat == QCF_FTEH2) && (newtype != QCF_HEXEN2 && newtype != QCF_UHEXEN2 && newtype != QCF_FTEH2))
QCC_PR_ParseWarning(WARN_BADTARGET, "Cannot switch from hexen2 target \'%s\' after the first statement. Ignored.", msg);
if ((newtype == QCF_HEXEN2 || newtype == QCF_UHEXEN2 || newtype == QCF_FTEH2) && (qcc_targetformat != QCF_HEXEN2 && qcc_targetformat != QCF_UHEXEN2 && qcc_targetformat != QCF_FTEH2))
QCC_PR_ParseWarning(WARN_BADTARGET, "Cannot switch to hexen2 target \'%s\' after the first statement. Ignored.", msg);
}
QCC_OPCodeSetTarget(newtype);
}
else if (!QC_strcasecmp(qcc_token, "PROGS_SRC"))
{ //doesn't make sence, but silenced if you are switching between using a certain precompiler app used with CuTF.
@ -5193,7 +5159,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
// name = QCC_PR_CheckCompConstString(name);
//accessors
if (QCC_PR_CheckKeyword (keyword_class, "accessor"))
if (QCC_PR_CheckKeyword (keyword_accessor, "accessor"))
{
char parentname[256];
char *accessorname;
@ -6036,7 +6002,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
if (QCC_PR_CheckToken("="))
{
defaultval = QCC_PR_ParseDefaultInitialiser(type);
QCC_PR_ParseWarning(ERR_INTERNAL, "TODO: initialised struct members are not implemented yet", type->name);
QCC_PR_ParseWarning(ERR_INTERNAL, "TODO: pre-initialised struct members are not implemented yet", type->name);
}
}

View file

@ -128,6 +128,7 @@ extern int dotranslate_count;
unsigned char qccwarningaction[WARN_MAX]; //0 = disabled, 1 = warn, 2 = error.
unsigned int qcc_targetversion;
qcc_targetformat_t qcc_targetformat;
pbool bodylessfuncs;
@ -224,6 +225,7 @@ struct {
{" F324", WARN_FORMATSTRING},
{" F325", WARN_NESTEDCOMMENT},
{" F326", WARN_DEPRECATEDVARIABLE},
{" F327", WARN_ENUMFLAGS_NOTINTEGER},
{" F207", WARN_NOTREFERENCEDFIELD},
{" F208", WARN_NOTREFERENCEDCONST},
@ -316,6 +318,7 @@ compiler_flag_t compiler_flag[] = {
{&keyword_break, defaultkeyword, "break", "Keyword: break", "Disables the 'break' keyword."},
{&keyword_case, defaultkeyword, "case", "Keyword: case", "Disables the 'case' keyword."},
{&keyword_class, defaultkeyword, "class", "Keyword: class", "Disables the 'class' keyword."},
{&keyword_accessor, defaultkeyword, "accessor", "Keyword: accessor", "Disables the 'accessor' keyword."},
{&keyword_const, defaultkeyword, "const", "Keyword: const", "Disables the 'const' keyword."},
{&keyword_continue, defaultkeyword, "continue", "Keyword: continue", "Disables the 'continue' keyword."},
{&keyword_default, defaultkeyword, "default", "Keyword: default", "Disables the 'default' keyword."},
@ -399,31 +402,6 @@ compiler_flag_t compiler_flag[] = {
{NULL}
};
struct {
qcc_targetformat_t target;
char *name;
} targets[] = {
{QCF_STANDARD, "standard"},
{QCF_STANDARD, "q1"},
{QCF_STANDARD, "id"},
{QCF_STANDARD, "quakec"},
{QCF_HEXEN2, "hexen2"},
{QCF_HEXEN2, "h2"},
{QCF_UHEXEN2, "uhexen2"},
{QCF_KK7, "kkqwsv"},
{QCF_KK7, "kk7"},
{QCF_KK7, "bigprogs"},
{QCF_KK7, "version7"},
{QCF_KK7, "kkqwsv"},
{QCF_FTE, "fte"},
{QCF_FTEH2, "fteh2"},
{QCF_DARKPLACES,"darkplaces"},
{QCF_DARKPLACES,"dp"},
{QCF_QTEST, "qtest"},
{0, NULL}
};
static const char *QCC_VersionString(void)
{
#if defined(SVNREVISION) && defined(SVNDATE)
@ -1181,6 +1159,13 @@ static void QCC_FinaliseDef(QCC_def_t *def)
def->symboldata = qcc_pr_globals + def->ofs;
def->symbolsize = numpr_globals - def->ofs;
if (def->reloc)
{
def->reloc->used = true;
QCC_FinaliseDef(def->reloc);
qcc_pr_globals[def->ofs]._int += def->reloc->ofs;
}
#ifdef DEBUG_DUMP_GLOBALMAP
if (!def->referenced)
externs->Printf("Unreferenced ");
@ -1434,6 +1419,7 @@ static pbool QCC_WriteData (int crc)
{
case QCF_HEXEN2:
case QCF_STANDARD:
case QCF_DARKPLACES: //grr.
if (bodylessfuncs)
externs->Printf("Warning: There are some functions without bodies.\n");
@ -1465,6 +1451,11 @@ static pbool QCC_WriteData (int crc)
externs->Printf("Progs execution requires a Hexen2 compatible HCVM\n");
break;
}
else if (qcc_targetformat == QCF_DARKPLACES)
{
externs->Printf("Progs execution uses extended opcodes.\n");
break;
}
else
{
if (numpr_globals >= 32768) //not much of a different format. Rewrite output to get it working on original executors?
@ -1473,12 +1464,12 @@ static pbool QCC_WriteData (int crc)
externs->Printf("Progs should run on any QuakeC VM\n");
break;
}
QCC_OPCodeSetTarget((qcc_targetformat==QCF_HEXEN2)?QCF_FTEH2:QCF_FTE);
QCC_OPCodeSetTarget((qcc_targetformat==QCF_HEXEN2)?QCF_FTEH2:QCF_FTE, 0);
//intentional fallthrough
case QCF_FTEDEBUG:
case QCF_FTE:
case QCF_FTEH2:
case QCF_DARKPLACES:
case QCF_QSS:
if (qcc_targetformat == QCF_FTEDEBUG)
debugtarget = true;
@ -1496,7 +1487,7 @@ static pbool QCC_WriteData (int crc)
}
}
if (qcc_targetformat == QCF_DARKPLACES)
if (qcc_targetformat == QCF_QSS || qcc_targetformat == QCF_DARKPLACES)
compressoutput = 0;
@ -1520,7 +1511,9 @@ static pbool QCC_WriteData (int crc)
if (verbose)
{
if (qcc_targetformat == QCF_DARKPLACES)
if (qcc_targetformat == QCF_QSS)
externs->Printf("QSS or FTE will be required\n");
else if (qcc_targetformat == QCF_DARKPLACES)
externs->Printf("DarkPlaces or FTE will be required\n");
else if (outputsttype == PST_UHEXEN2)
externs->Printf("FTE or uHexen2 will be required\n");
@ -2440,18 +2433,23 @@ strofs = (strofs+3)&~3;
case QCF_FTE:
case QCF_FTEH2:
case QCF_FTEDEBUG:
case QCF_QSS:
case QCF_UHEXEN2:
case QCF_KK7:
progs.version = PROG_EXTENDEDVERSION;
progs.version = PROG_EXTENDEDVERSION;
if (outputsttype == PST_UHEXEN2)
progs.secondaryversion = PROG_SECONDARYUHEXEN2; //prepadded...
else if (outputsttype == QCF_KK7)
else if (outputsttype == PST_KKQWSV)
progs.secondaryversion = PROG_SECONDARYKKQWSV; //messed up
else if (outputsttype == PST_FTE32)
progs.secondaryversion = PROG_SECONDARYVERSION32; //post-extended.
else
{
progs.secondaryversion = PROG_SECONDARYVERSION16;
if (qcc_targetformat == QCF_DARKPLACES)
progs.version = PROG_VERSION;
}
if (debugtarget && statement_linenums)
{
@ -2581,6 +2579,9 @@ strofs = (strofs+3)&~3;
case QCF_DARKPLACES:
externs->Printf("Compile finished: %s (patched-dp format)\n", destfile);
break;
case QCF_QSS:
externs->Printf("Compile finished: %s (fte+qss format)\n", destfile);
break;
case QCF_FTE:
externs->Printf("Compile finished: %s (fte format)\n", destfile);
break;
@ -3215,7 +3216,7 @@ static void QCC_PR_BeginCompilation (void *memory, int memsize)
type_function = QCC_PR_NewType("__function", ev_function, false);
type_function->aux_type = type_void;
type_pointer = QCC_PR_NewType("__pointer", ev_pointer, false);
type_integer = QCC_PR_NewType("__integer", ev_integer, true);
type_integer = QCC_PR_NewType("__int", ev_integer, true);
type_variant = QCC_PR_NewType("__variant", ev_variant, true);
type_floatfield = QCC_PR_NewType("__fieldfloat", ev_field, false);
@ -3237,7 +3238,7 @@ static void QCC_PR_BeginCompilation (void *memory, int memsize)
QCC_PR_NewType("variant", ev_variant, true);
QCC_PR_NewType("integer", ev_integer, keyword_integer?true:false);
QCC_PR_NewType("int", ev_integer, keyword_integer?true:false);
QCC_PR_NewType("int", ev_integer, keyword_int?true:false);
@ -4225,7 +4226,33 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
else
*compiler_flag[p].enabled = false;
}
if (!strcmp(myargv[i]+5, "qccx"))
if (!stricmp(myargv[i]+5, "C"))
{ //set up for greatest C compatibility... variations from C are bugs, not features.
keyword_asm = false;
keyword_break = keyword_continue = keyword_for = keyword_goto = keyword_const = keyword_extern = keyword_static = true;
keyword_switch = keyword_case = keyword_default = true;
keyword_accessor = keyword_class = keyword_var = keyword_inout = keyword_optional = keyword_state = keyword_inline = keyword_nosave = keyword_shared = keyword_noref = keyword_unused = keyword_used = keyword_nonstatic = keyword_ignore = keyword_strip = false;
keyword_vector = keyword_entity = keyword_float = keyword_string = false; //not to be confused with actual types, but rather the absence of the keyword local.
keyword_integer = keyword_enumflags = false;
keyword_float = keyword_int = keyword_typedef = keyword_struct = keyword_union = keyword_enum = true;
keyword_thinktime = keyword_until = keyword_loop = false;
keyword_integer = true;
opt_logicops = true; //early out like C.
flag_assumevar = true; //const only if explicitly const.
pr_subscopedlocals = true; //locals shadow other locals rather than being the same one.
flag_cpriority = true; //fiddle with operator precedence.
flag_assume_integer = true;
qccwarningaction[WARN_UNINITIALIZED] = WA_WARN; //C doesn't like that, might as well warn here too.
qccwarningaction[WARN_TOOMANYPARAMS] = WA_ERROR; //too many args to function is weeeeird.
qccwarningaction[WARN_TOOFEWPARAMS] = WA_ERROR; //missing args should be fatal.
qccwarningaction[WARN_ASSIGNMENTTOCONSTANT] = WA_ERROR; //const is const. at least its not const by default.
qccwarningaction[WARN_SAMENAMEASGLOBAL] = WA_IGNORE; //shadowing of globals.
}
else if (!strcmp(myargv[i]+5, "qccx"))
{
flag_qccx = true; //fixme: extra stuff
qccwarningaction[WARN_DENORMAL] = WA_IGNORE; //this is just too spammy
@ -4249,7 +4276,7 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
keyword_asm = keyword_break = keyword_continue = keyword_for = keyword_goto = false;
keyword_const = keyword_var = keyword_inout = keyword_optional = keyword_state = keyword_inline = keyword_nosave = keyword_extern = keyword_shared = keyword_noref = keyword_unused = keyword_used = keyword_static = keyword_nonstatic = keyword_ignore = keyword_strip = false;
keyword_switch = keyword_case = keyword_default = keyword_class = keyword_const = false;
keyword_switch = keyword_case = keyword_default = keyword_accessor = keyword_class = keyword_const = false;
keyword_vector = keyword_entity = keyword_float = keyword_string = false; //not to be confused with actual types, but rather the absence of the keyword local.
keyword_int = keyword_integer = keyword_typedef = keyword_struct = keyword_union = keyword_enum = keyword_enumflags = false;
@ -4262,7 +4289,7 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
keyword_asm = keyword_continue = keyword_for = keyword_goto = false;
keyword_const = keyword_var = keyword_inout = keyword_optional = keyword_state = keyword_inline = keyword_nosave = keyword_extern = keyword_shared = keyword_noref = keyword_unused = keyword_used = keyword_static = keyword_nonstatic = keyword_ignore = keyword_strip = false;
keyword_class = keyword_const = false;
keyword_accessor = keyword_class = keyword_const = false;
keyword_vector = keyword_entity = keyword_float = keyword_string = false; //not to be confused with actual types, but rather the absence of the keyword local.
keyword_int = keyword_integer = keyword_typedef = keyword_struct = keyword_union = keyword_enum = keyword_enumflags = false;
@ -4291,7 +4318,7 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
keyword_asm = false;
keyword_inout = keyword_optional = keyword_state = keyword_inline = keyword_nosave = keyword_extern = keyword_shared = keyword_unused = keyword_used = keyword_nonstatic = keyword_ignore = keyword_strip = false;
keyword_class = false;
keyword_accessor = keyword_class = false;
keyword_vector = keyword_entity = keyword_float = keyword_string = false; //not to be confused with actual types, but rather the absence of the keyword local.
keyword_int = keyword_integer = keyword_struct = keyword_union = keyword_enum = keyword_enumflags = false;
@ -4370,14 +4397,7 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
parseonly = true;
else
{
for (p = 0; targets[p].name; p++)
if (!stricmp(myargv[i]+2, targets[p].name))
{
QCC_OPCodeSetTarget(targets[p].target);
break;
}
if (!targets[p].name)
if (!QCC_OPCodeSetTargetName(myargv[i]+2))
QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised target parameter (%s)", myargv[i]);
}
}
@ -4571,7 +4591,7 @@ static void QCC_SetDefaultProperties (void)
}
}
{
{ //FIXME: outdated, should be using -Tfte
qcc_targetformat_t targ;
if (QCC_CheckParm ("-h2"))
targ = QCF_HEXEN2;
@ -4583,7 +4603,7 @@ static void QCC_SetDefaultProperties (void)
targ = QCF_DARKPLACES;
else
targ = QCF_STANDARD;
QCC_OPCodeSetTarget(targ);
QCC_OPCodeSetTarget(targ, 0x7fffffff);
}