From 6d62e91ce7d809fed8ba8078d0894b201ab12ebb Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Apr 2022 15:10:00 +0900 Subject: [PATCH 01/34] [gamecode] Clean up progs data access pr_type_t now contains only the one "value" field, and all the access macros now use their PACKED variant for base access, making access to larger types more consistent with the smaller types. --- include/QF/progs.h | 130 ++++++++++++++++++---------- include/QF/progs/pr_comp.h | 18 ++-- libs/gamecode/pr_debug.c | 60 ++++++------- libs/gamecode/pr_exec.c | 144 ++++++++++++++----------------- libs/gamecode/pr_parse.c | 30 +++---- libs/gamecode/pr_strings.c | 4 +- libs/gib/bi_gib.c | 3 +- libs/ruamoko/pr_cmds.c | 4 +- libs/ruamoko/rua_hash.c | 6 +- libs/ruamoko/rua_obj.c | 8 +- nq/include/sv_progs.h | 8 +- nq/source/sv_pr_cmds.c | 2 +- qw/include/sv_progs.h | 8 +- qw/source/sv_pr_cmds.c | 2 +- qw/source/sv_progs.c | 20 ++--- tools/qfcc/include/obj_file.h | 2 +- tools/qfcc/include/qfcc.h | 11 +-- tools/qfcc/source/def.c | 4 +- tools/qfcc/source/dump_globals.c | 2 +- tools/qfcc/source/obj_file.c | 2 +- tools/qfcc/source/qfcc.c | 4 +- tools/qfcc/source/reloc.c | 4 +- tools/qfcc/source/struct.c | 2 +- tools/qfcc/source/value.c | 2 +- 24 files changed, 248 insertions(+), 232 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index b90c96e99..958bbd767 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -403,16 +403,6 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ ///@{ -/** \internal - \param p pointer to ::progs_t VM struct - \param o offset into global data space - \param t typename prefix (see pr_type_u) - \return lvalue of the appropriate type - - \hideinitializer -*/ -#define G_var(p,o,t) ((p)->pr_globals[o].t##_var) - /** Access a global as an arbitray type. More direct than G_STRUCT @@ -428,6 +418,16 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define G_PACKED(p,t,o) (*(t *) &(p)->pr_globals[o]) +/** \internal + \param p pointer to ::progs_t VM struct + \param o offset into global data space + \param t typename prefix (see pr_type_u) + \return lvalue of the appropriate type + + \hideinitializer +*/ +#define G_var(p,o,t) G_PACKED(p, pr_##t##_t, o) + /** Access a float global. Can be assigned to. \par QC type: @@ -450,7 +450,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define G_DOUBLE(p,o) (*(double *) ((p)->pr_globals + o)) +#define G_DOUBLE(p,o) G_var (p, o, double) /** Access an int global. Can be assigned to. @@ -486,7 +486,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define G_VECTOR(p,o) (&G_var (p, o, vector)) +#define G_VECTOR(p,o) (&G_var (p, o, float)) /** Access a quaternion global. Can be assigned to. @@ -498,7 +498,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define G_QUAT(p,o) (&G_var (p, o, quat)) +#define G_QUAT(p,o) (&G_var (p, o, float)) /** Access a string index global. Can be assigned to. @@ -534,8 +534,31 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define G_POINTER(p,o) G_var (p, o, pointer) +#define G_POINTER(p,o) G_var (p, o, ptr) +/** Access a field global. + + \par QC type: + \c field + \param p pointer to ::progs_t VM struct + \param o offset into global data space + \return field offset + + \hideinitializer +*/ +#define G_FIELD(p,o) G_var (p, o, field) + +/** Access an entity global. + + \par QC type: + \c entity + \param p pointer to ::progs_t VM struct + \param o offset into global data space + \return entity "pointer" + + \hideinitializer +*/ +#define G_ENTITY(p,o) G_var (p, o, entity) /** Access an entity global. @@ -620,16 +643,6 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ ///@{ -/** \internal - \param p pointer to ::progs_t VM struct - \param n parameter number (0-7) - \param t typename prefix (see pr_type_u) - \return lvalue of the appropriate type - - \hideinitializer -*/ -#define P_var(p,n,t) ((p)->pr_params[n]->t##_var) - /** Access a parameter as an arbitray type. \par QC type: @@ -644,6 +657,16 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define P_PACKED(p,t,n) (*(t *) (p)->pr_params[n]) +/** \internal + \param p pointer to ::progs_t VM struct + \param n parameter number (0-7) + \param t typename prefix (see pr_type_u) + \return lvalue of the appropriate type + + \hideinitializer +*/ +#define P_var(p,n,t) P_PACKED(p, pr_##t##_t, n) + /** Access a float parameter. Can be assigned to. \par QC type: @@ -666,7 +689,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define P_DOUBLE(p,n) P_PACKED(p, double, n) +#define P_DOUBLE(p,n) P_var (p, n, double) /** Access an int parameter. Can be assigned to. @@ -702,7 +725,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define P_VECTOR(p,n) (&P_var (p, n, vector)) +#define P_VECTOR(p,n) (&P_var (p, n, float)) /** Access a quaterion parameter. Can be used any way a quat_t variable can. @@ -714,7 +737,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define P_QUAT(p,n) (&P_var (p, n, quat)) +#define P_QUAT(p,n) (&P_var (p, n, float)) /** Access a string index parameter. Can be assigned to. @@ -750,7 +773,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define P_POINTER(p,n) P_var (p, n, pointer) +#define P_POINTER(p,n) P_var (p, n, ptr) /** Access an entity parameter. @@ -839,16 +862,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ ///@{ -/** \internal - \param p pointer to ::progs_t VM struct - \param t typename prefix (see pr_type_u) - \return lvalue of the appropriate type - - \hideinitializer -*/ -#define R_var(p,t) ((p)->pr_return->t##_var) - -/** Access the VM function return value parameter as an arbitray type. +/** Access the VM function return value as an arbitray type. \par QC type: \c struct etc small enough to fit in the return slot @@ -861,6 +875,15 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define R_PACKED(p,t) (*(t *) (p)->pr_return) +/** \internal + \param p pointer to ::progs_t VM struct + \param t typename prefix (see pr_type_u) + \return lvalue of the appropriate type + + \hideinitializer +*/ +#define R_var(p,t) R_PACKED(p, pr_##t##_t) + /** Access the VM function return value as a \c float \par QC type: @@ -881,7 +904,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define R_DOUBLE(p) R_PACKED (p, double) +#define R_DOUBLE(p) R_var (p, double) /** Access the VM function return value as a \c ::pr_int_t (AKA int32_t) @@ -914,7 +937,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define R_VECTOR(p) (&R_var (p, vector)) +#define R_VECTOR(p) (&R_var (p, float)) /** Access the VM function return value as a \c ::quat_t quaternion. @@ -925,7 +948,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define R_QUAT(p) (&R_var (p, quat)) +#define R_QUAT(p) (&R_var (p, float)) /** Access the VM function return value as a ::pr_string_t (a VM string reference). @@ -958,7 +981,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define R_POINTER(p) R_var (p, pointer) +#define R_POINTER(p) R_var (p, ptr) /** Set the return value to the given C string. The returned string will @@ -1036,6 +1059,19 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define E_fld(e,o) ((e)->pr->pr_edict_area[(e)->edict + (o)]) +/** Access an entity field as an arbitray type. + + \par QC type: + \c struct etc small enough to fit in a single parameter + \param e pointer to the entity + \param t C type of the structure + \param o field offset into entity data space + \return structure lvalue. use & to make a pointer of the + appropriate type. + + \hideinitializer +*/ +#define E_PACKED(e,t,o) (*(t *) &E_fld (e, o)) /** \internal \param e pointer to the entity @@ -1045,7 +1081,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define E_var(e,o,t) (E_fld (e,o).t##_var) +#define E_var(e,o,t) E_PACKED (e, pr_##t##_t,o) /** Access a float entity field. Can be assigned to. @@ -1070,7 +1106,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define E_DOUBLE(e,o) (*(double *) ((e)->v + o)) +#define E_DOUBLE(e,o) E_var (e, o, double) /** Access an int entity field. Can be assigned to. @@ -1106,7 +1142,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define E_VECTOR(e,o) (&E_var (e, o, vector)) +#define E_VECTOR(e,o) (&E_var (e, o, float)) /** Access a quaternion entity field. Can be used any way a quat_t variable can. @@ -1119,7 +1155,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define E_QUAT(e,o) E_var (e, o, quat) +#define E_QUAT(e,o) E_var (e, o, float) /** Access a string index entity field. Can be assigned to. @@ -1155,7 +1191,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define E_POINTER(e,o) E_var (e, o, pointer) +#define E_POINTER(e,o) E_var (e, o, ptr) /** Access a string entity field, converting it to a C string. Kills the diff --git a/include/QF/progs/pr_comp.h b/include/QF/progs/pr_comp.h index bc0c1030e..cef8c3ef6 100644 --- a/include/QF/progs/pr_comp.h +++ b/include/QF/progs/pr_comp.h @@ -39,6 +39,8 @@ typedef int64_t pr_long_t __attribute__((aligned(8))); typedef uint64_t pr_ulong_t __attribute__((aligned(8))); typedef uint16_t pr_ushort_t __attribute__((aligned(2)));; +#define PR_PTR(t, p) (*(pr_##t##_t *) (p)) + #define PR_VEC_TYPE(t,n,s) \ typedef t n __attribute__ ((vector_size (s*sizeof (t)))) @@ -538,16 +540,12 @@ typedef struct dfunction_s { dparmsize_t param_size[PR_MAX_PARAMS]; } dfunction_t; -typedef union pr_type_u { - float float_var; - pr_string_t string_var; - pr_func_t func_var; - pr_uint_t entity_var; - float vector_var; // really [3], but this structure must be 32 bits - float quat_var; // really [4], but this structure must be 32 bits - pr_int_t int_var; - pr_ptr_t pointer_var; - pr_uint_t uint_var; +typedef struct pr_type_s { + union { + pr_int_t value; + pr_uint_t uint_value; + pr_float_t float_value; + }; } pr_type_t; typedef pr_type_t pr_void_t; // so size of void is 1 diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index d27255e11..2f3d4905f 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -337,11 +337,11 @@ parse_expression (progs_t *pr, const char *expr, int conditional) goto error; if (!Script_GetToken (es, 1)) goto error; - pr->wp_val.int_var = strtol (es->token->str, &e, 0); + PR_PTR (int, &pr->wp_val) = strtol (es->token->str, &e, 0); if (e == es->token->str) goto error; if (*e == '.' || *e == 'e' || *e == 'E') - pr->wp_val.float_var = strtod (es->token->str, &e); + PR_PTR (float, &pr->wp_val) = strtod (es->token->str, &e); pr->wp_conditional = 1; } } @@ -385,7 +385,7 @@ pr_debug_clear (progs_t *pr, void *data) pr->watch = 0; pr->wp_conditional = 0; - pr->wp_val.int_var = 0; + PR_PTR (int, &pr->wp_val) = 0; for (int i = 0; i < ev_type_count; i++ ) { res->type_encodings[i] = &res->void_type; @@ -612,7 +612,7 @@ PR_LoadDebug (progs_t *pr) if (!str) return 1; - res->debugfile = PR_GetString (pr, str->string_var); + res->debugfile = PR_GetString (pr, PR_PTR (string, str)); sym_file = QFS_SkipPath (res->debugfile); path_end = QFS_SkipPath (pr->progs_name); sym_path = malloc (strlen (sym_file) + (path_end - pr->progs_name) + 1); @@ -1152,7 +1152,7 @@ pr_debug_string_view (qfot_type_t *type, pr_type_t *value, void *_data) { __auto_type data = (pr_debug_data_t *) _data; dstring_t *dstr = data->dstr; - pr_string_t string = value->string_var; + pr_string_t string = PR_PTR (string, value); if (PR_StringValid (data->pr, string)) { const char *str = PR_GetString (data->pr, string); @@ -1196,11 +1196,11 @@ pr_debug_float_view (qfot_type_t *type, pr_type_t *value, void *_data) dstring_t *dstr = data->dstr; if (data->pr->progs->version == PROG_ID_VERSION - && ISDENORM (value->int_var) - && value->uint_var != 0x80000000) { - dasprintf (dstr, "<%08x>", value->int_var); + && ISDENORM (PR_PTR (int, value)) + && PR_PTR (uint, value) != 0x80000000) { + dasprintf (dstr, "<%08x>", PR_PTR (int, value)); } else { - dasprintf (dstr, "%.9g", value->float_var); + dasprintf (dstr, "%.9g", PR_PTR (float, value)); } } @@ -1210,7 +1210,7 @@ pr_debug_vector_view (qfot_type_t *type, pr_type_t *value, void *_data) __auto_type data = (pr_debug_data_t *) _data; dstring_t *dstr = data->dstr; - dasprintf (dstr, "'%.9g %.9g %.9g'", VectorExpand (&value->vector_var)); + dasprintf (dstr, "'%.9g %.9g %.9g'", VectorExpand (&PR_PTR (float, value))); } static void @@ -1221,15 +1221,15 @@ pr_debug_entity_view (qfot_type_t *type, pr_type_t *value, void *_data) dstring_t *dstr = data->dstr; if (pr->pr_edicts - && value->entity_var < pr->max_edicts - && !(value->entity_var % pr->pr_edict_size)) { - edict_t *edict = PROG_TO_EDICT (pr, value->entity_var); + && PR_PTR (entity, value) < pr->max_edicts + && !(PR_PTR (entity, value) % pr->pr_edict_size)) { + edict_t *edict = PROG_TO_EDICT (pr, PR_PTR (entity, value)); if (edict) { dasprintf (dstr, "entity %d", NUM_FOR_BAD_EDICT (pr, edict)); return; } } - dasprintf (dstr, "entity [%x]", value->entity_var); + dasprintf (dstr, "entity [%x]", PR_PTR (entity, value)); } static void @@ -1238,12 +1238,12 @@ pr_debug_field_view (qfot_type_t *type, pr_type_t *value, void *_data) __auto_type data = (pr_debug_data_t *) _data; progs_t *pr = data->pr; dstring_t *dstr = data->dstr; - pr_def_t *def = PR_FieldAtOfs (pr, value->int_var); + pr_def_t *def = PR_FieldAtOfs (pr, PR_PTR (int, value)); if (def) { dasprintf (dstr, ".%s", PR_GetString (pr, def->name)); } else { - dasprintf (dstr, ".<$%04x>", value->int_var); + dasprintf (dstr, ".<$%04x>", PR_PTR (int, value)); } } @@ -1254,12 +1254,12 @@ pr_debug_func_view (qfot_type_t *type, pr_type_t *value, void *_data) progs_t *pr = data->pr; dstring_t *dstr = data->dstr; - if (value->func_var >= pr->progs->functions.count) { - dasprintf (dstr, "INVALID:%d", value->func_var); - } else if (!value->func_var) { + if (PR_PTR (func, value) >= pr->progs->functions.count) { + dasprintf (dstr, "INVALID:%d", PR_PTR (func, value)); + } else if (!PR_PTR (func, value)) { dstring_appendstr (dstr, "NULL"); } else { - dfunction_t *f = pr->pr_functions + value->func_var; + dfunction_t *f = pr->pr_functions + PR_PTR (func, value); dasprintf (dstr, "%s()", PR_GetString (pr, f->name)); } } @@ -1270,7 +1270,7 @@ pr_debug_ptr_view (qfot_type_t *type, pr_type_t *value, void *_data) __auto_type data = (pr_debug_data_t *) _data; progs_t *pr = data->pr; dstring_t *dstr = data->dstr; - pr_ptr_t offset = value->int_var; + pr_ptr_t offset = PR_PTR (int, value); pr_ptr_t offs = offset; pr_def_t *def = 0; @@ -1292,7 +1292,7 @@ pr_debug_quaternion_view (qfot_type_t *type, pr_type_t *value, void *_data) __auto_type data = (pr_debug_data_t *) _data; dstring_t *dstr = data->dstr; - dasprintf (dstr, "'%.9g %.9g %.9g %.9g'", QuatExpand (&value->quat_var)); + dasprintf (dstr, "'%.9g %.9g %.9g %.9g'", QuatExpand (&PR_PTR (float, value))); } static void @@ -1301,7 +1301,7 @@ pr_debug_int_view (qfot_type_t *type, pr_type_t *value, void *_data) __auto_type data = (pr_debug_data_t *) _data; dstring_t *dstr = data->dstr; - dasprintf (dstr, "%d", value->int_var); + dasprintf (dstr, "%d", PR_PTR (int, value)); } static void @@ -1310,7 +1310,7 @@ pr_debug_uint_view (qfot_type_t *type, pr_type_t *value, void *_data) __auto_type data = (pr_debug_data_t *) _data; dstring_t *dstr = data->dstr; - dasprintf (dstr, "$%08x", value->uint_var); + dasprintf (dstr, "$%08x", PR_PTR (uint, value)); } static void @@ -1319,7 +1319,7 @@ pr_debug_short_view (qfot_type_t *type, pr_type_t *value, void *_data) __auto_type data = (pr_debug_data_t *) _data; dstring_t *dstr = data->dstr; - dasprintf (dstr, "%04x", (short)value->int_var); + dasprintf (dstr, "%04x", (short)PR_PTR (int, value)); } static void @@ -1355,7 +1355,7 @@ pr_debug_ushort_view (qfot_type_t *type, pr_type_t *value, void *_data) __auto_type data = (pr_debug_data_t *) _data; dstring_t *dstr = data->dstr; - dasprintf (dstr, "%04x", (pr_ushort_t)value->int_var); + dasprintf (dstr, "%04x", (pr_ushort_t)PR_PTR (int, value)); } static void @@ -1431,7 +1431,7 @@ PR_Debug_Watch (progs_t *pr, const char *expr) (int) (intptr_t) (pr->watch - pr->pr_globals)); if (pr->wp_conditional) Sys_Printf (" if new val == %d\n", - pr->wp_val.int_var); + PR_PTR (int, &pr->wp_val)); } else { Sys_Printf (" none active\n"); } return; @@ -1444,7 +1444,7 @@ PR_Debug_Watch (progs_t *pr, const char *expr) if (pr->watch) { Sys_Printf ("watchpoint set to [%d]\n", PR_SetPointer (pr, pr->watch)); if (pr->wp_conditional) - Sys_Printf (" if new val == %d\n", pr->wp_val.int_var); + Sys_Printf (" if new val == %d\n", PR_PTR (int, &pr->wp_val)); } else { Sys_Printf ("watchpoint cleared\n"); } @@ -1683,8 +1683,8 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) case 'E': { edict_t *ed = 0; - opval = pr->pr_globals[s->a].entity_var; - param_ind = pr->pr_globals[s->b].uint_var; + opval = G_ENTITY (pr, s->a); + param_ind = G_FIELD (pr, s->b); if (param_ind < pr->progs->entityfields && opval > 0 && opval < pr->pr_edict_area_size) { diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index a7d4fbac7..e8c4f2551 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -287,7 +287,7 @@ PR_EnterFunction (progs_t *pr, bfunction_t *f) if (pr_deadbeef_locals) { for (pr_uint_t i = f->params_start; i < f->params_start + f->locals; i++) { - pr->pr_globals[i].int_var = 0xdeadbeef; + pr->pr_globals[i].value = 0xdeadbeef; } } @@ -304,8 +304,8 @@ PR_EnterFunction (progs_t *pr, bfunction_t *f) copy_param (dstParams[i], pr->pr_params[i], f->param_size[i].size); } copy_args = pr->pr_argc - i; - argc->int_var = copy_args; - argv->int_var = dstParams[i] - pr->pr_globals; + PR_PTR (int, argc) = copy_args; + PR_PTR (ptr, argv) = PR_SetPointer (pr, dstParams[i]); if (i < PR_MAX_PARAMS) { memcpy (dstParams[i], pr->pr_params[i], (copy_args * pr->pr_param_size) * sizeof (pr_type_t)); @@ -517,7 +517,7 @@ static inline void pr_memset (pr_type_t *dst, int val, pr_uint_t count) { while (count-- > 0) { - (*dst++).int_var = val; + (*dst++).value = val; } } @@ -839,7 +839,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_int); } ptr = pr->pr_globals + pointer; - ptr->int_var = OPA(int); + ptr->value = OPA(int); break; case OP_STOREP_V_v6p: pointer = OPB(ptr); @@ -847,7 +847,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; - VectorCopy (&OPA(float), &ptr->vector_var); + VectorCopy (&OPA(float), &PR_PTR (float, ptr)); break; case OP_STOREP_Q_v6p: pointer = OPB(ptr); @@ -855,7 +855,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_quaternion); } ptr = pr->pr_globals + pointer; - QuatCopy (&OPA(float), &ptr->quat_var); + QuatCopy (&OPA(float), &PR_PTR (float, ptr)); break; case OP_STOREP_D_v6p: pointer = OPB(ptr); @@ -910,7 +910,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) "field in an edict"); } fldofs = OPA(entity) + OPB(field); - OPC(int) = pr->pr_edict_area[fldofs].int_var; + OPC(int) = PR_PTR (int, &pr->pr_edict_area[fldofs]); break; case OP_LOAD_V_v6p: if (pr_boundscheck) { @@ -961,23 +961,21 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_int); } ptr = pr->pr_globals + pointer; - OPC(int) = ptr->int_var; + OPC(int) = ptr->value; break; case OP_LOADB_V_v6p: pointer = OPA(entity) + OPB(field); if (pr_boundscheck) { PR_BoundsCheck (pr, pointer, ev_vector); } - ptr = pr->pr_globals + pointer; - VectorCopy (&ptr->vector_var, &OPC(float)); + VectorCopy (G_VECTOR (pr, pointer), &OPC(float)); break; case OP_LOADB_Q_v6p: pointer = OPA(entity) + OPB(field); if (pr_boundscheck) { PR_BoundsCheck (pr, pointer, ev_quaternion); } - ptr = pr->pr_globals + pointer; - QuatCopy (&ptr->quat_var, &OPC(float)); + QuatCopy (G_QUAT (pr, pointer), &OPC(float)); break; case OP_LOADB_D_v6p: pointer = OPA(entity) + OPB(field); @@ -1000,7 +998,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_int); } ptr = pr->pr_globals + pointer; - OPC(int) = ptr->int_var; + OPC(int) = ptr->value; break; case OP_LOADBI_V_v6p: pointer = OPA(ptr) + (short) st->b; @@ -1008,7 +1006,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; - VectorCopy (&ptr->vector_var, &OPC(float)); + VectorCopy (G_VECTOR (pr, pointer), &OPC(float)); break; case OP_LOADBI_Q_v6p: pointer = OPA(ptr) + (short) st->b; @@ -1016,7 +1014,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_quaternion); } ptr = pr->pr_globals + pointer; - QuatCopy (&ptr->quat_var, &OPC(float)); + QuatCopy (G_QUAT (pr, pointer), &OPC(float)); break; case OP_LOADBI_D_v6p: pointer = OPA(ptr) + (short) st->b; @@ -1049,7 +1047,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_int); } ptr = pr->pr_globals + pointer; - ptr->int_var = OPA(int); + ptr->value = OPA(int); break; case OP_STOREB_V_v6p: pointer = OPB(ptr) + OPC(int); @@ -1057,7 +1055,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; - VectorCopy (&OPA(float), &ptr->vector_var); + VectorCopy (&OPA(float), G_VECTOR (pr, pointer)); break; case OP_STOREB_Q_v6p: pointer = OPB(ptr) + OPC(int); @@ -1065,7 +1063,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_quaternion); } ptr = pr->pr_globals + pointer; - QuatCopy (&OPA(float), &ptr->quat_var); + QuatCopy (&OPA(float), G_QUAT (pr, pointer)); break; case OP_STOREB_D_v6p: pointer = OPB(ptr) + OPC(int); @@ -1088,7 +1086,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_int); } ptr = pr->pr_globals + pointer; - ptr->int_var = OPA(int); + ptr->value = OPA(int); break; case OP_STOREBI_V_v6p: pointer = OPB(ptr) + (short) st->c; @@ -1096,7 +1094,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; - VectorCopy (&OPA(float), &ptr->vector_var); + VectorCopy (&OPA(float), G_VECTOR (pr, pointer)); break; case OP_STOREBI_Q_v6p: pointer = OPB(ptr) + (short) st->c; @@ -1104,7 +1102,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_quaternion); } ptr = pr->pr_globals + pointer; - QuatCopy (&OPA(float), &ptr->quat_var); + QuatCopy (&OPA(float), G_QUAT (pr, pointer)); break; case OP_STOREBI_D_v6p: pointer = OPB(ptr) + (short) st->c; @@ -1128,7 +1126,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) if (pr_boundscheck) { check_stack_pointer (pr, stack, 1); } - stk->int_var = OPA(int); + stk->value = OPA(int); *pr->globals.stack = stack; } break; @@ -1174,14 +1172,13 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_int); } - stk->int_var = ptr->int_var; + stk->value = ptr->value; *pr->globals.stack = stack; } break; case OP_PUSHB_V_v6p: { pr_ptr_t stack = *pr->globals.stack - 3; - pr_type_t *stk = pr->pr_globals + stack; pointer = OPA(ptr) + OPB(int); ptr = pr->pr_globals + pointer; @@ -1191,14 +1188,13 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_int); } - VectorCopy (&ptr->vector_var, &stk->vector_var); + VectorCopy (G_VECTOR (pr, pointer), G_VECTOR (pr, stack)); *pr->globals.stack = stack; } break; case OP_PUSHB_Q_v6p: { pr_ptr_t stack = *pr->globals.stack - 4; - pr_type_t *stk = pr->pr_globals + stack; pointer = OPA(ptr) + OPB(int); ptr = pr->pr_globals + pointer; @@ -1208,7 +1204,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_quaternion); } - QuatCopy (&ptr->quat_var, &stk->quat_var); + QuatCopy (G_QUAT (pr, pointer), G_QUAT (pr, stack)); *pr->globals.stack = stack; } break; @@ -1232,14 +1228,13 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_int); } - stk->int_var = ptr->int_var; + stk->value = ptr->value; *pr->globals.stack = stack; } break; case OP_PUSHBI_V_v6p: { pr_ptr_t stack = *pr->globals.stack - 3; - pr_type_t *stk = pr->pr_globals + stack; pointer = OPA(ptr) + st->b; ptr = pr->pr_globals + pointer; @@ -1249,14 +1244,13 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_int); } - VectorCopy (&ptr->vector_var, &stk->vector_var); + VectorCopy (G_VECTOR (pr, pointer), G_VECTOR (pr, stack)); *pr->globals.stack = stack; } break; case OP_PUSHBI_Q_v6p: { pr_ptr_t stack = *pr->globals.stack - 4; - pr_type_t *stk = pr->pr_globals + stack; pointer = OPA(ptr) + st->b; ptr = pr->pr_globals + pointer; @@ -1266,7 +1260,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_quaternion); } - QuatCopy (&ptr->quat_var, &stk->quat_var); + QuatCopy (G_QUAT (pr, pointer), G_QUAT (pr, stack)); *pr->globals.stack = stack; } break; @@ -1284,7 +1278,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) if (pr_boundscheck) { check_stack_pointer (pr, stack, 1); } - OPA(int) = stk->int_var; + OPA(int) = stk->value; *pr->globals.stack = stack + 1; } break; @@ -1330,14 +1324,13 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_int); } - ptr->int_var = stk->int_var; + ptr->value = stk->value; *pr->globals.stack = stack + 1; } break; case OP_POPB_V_v6p: { pr_ptr_t stack = *pr->globals.stack; - pr_type_t *stk = pr->pr_globals + stack; pointer = OPA(ptr) + OPB(int); ptr = pr->pr_globals + pointer; @@ -1347,14 +1340,13 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_int); } - VectorCopy (&stk->vector_var, &ptr->vector_var); + VectorCopy (G_VECTOR (pr, stack), G_VECTOR (pr, pointer)); *pr->globals.stack = stack + 3; } break; case OP_POPB_Q_v6p: { pr_ptr_t stack = *pr->globals.stack; - pr_type_t *stk = pr->pr_globals + stack; pointer = OPA(ptr) + OPB(int); ptr = pr->pr_globals + pointer; @@ -1364,7 +1356,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_quaternion); } - QuatCopy (&stk->quat_var, &ptr->quat_var); + QuatCopy (G_QUAT (pr, stack), G_QUAT (pr, pointer)); *pr->globals.stack = stack + 4; } break; @@ -1388,14 +1380,13 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_int); } - ptr->int_var = stk->int_var; + ptr->value = stk->value; *pr->globals.stack = stack + 1; } break; case OP_POPBI_V_v6p: { pr_ptr_t stack = *pr->globals.stack; - pr_type_t *stk = pr->pr_globals + stack; pointer = OPA(ptr) + st->b; ptr = pr->pr_globals + pointer; @@ -1405,14 +1396,13 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_int); } - VectorCopy (&stk->vector_var, &ptr->vector_var); + VectorCopy (G_VECTOR (pr, stack), G_VECTOR (pr, pointer)); *pr->globals.stack = stack + 3; } break; case OP_POPBI_Q_v6p: { pr_ptr_t stack = *pr->globals.stack; - pr_type_t *stk = pr->pr_globals + stack; pointer = OPA(ptr) + st->b; ptr = pr->pr_globals + pointer; @@ -1422,7 +1412,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) PR_BoundsCheck (pr, pointer, ev_quaternion); } - QuatCopy (&stk->quat_var, &ptr->quat_var); + QuatCopy (G_QUAT (pr, stack), G_QUAT (pr, pointer)); *pr->globals.stack = stack + 4; } break; @@ -1481,8 +1471,7 @@ pr_exec_quakec (progs_t *pr, int exitdepth) if (pr_boundscheck) { PR_BoundsCheck (pr, pointer, ev_int); } - ptr = pr->pr_globals + pointer; - pointer = ptr->int_var; + pointer = G_POINTER (pr, pointer); if (pr_boundscheck && (pointer >= pr->progs->statements.count)) { PR_RunError (pr, "Invalid jump destination"); @@ -1551,9 +1540,9 @@ op_call: int frame = pr->fields.frame + self; int think = pr->fields.think + self; float time = *pr->globals.ftime + 0.1; - pr->pr_edict_area[nextthink].float_var = time; - pr->pr_edict_area[frame].float_var = OPA(float); - pr->pr_edict_area[think].func_var = OPB(func); + PR_PTR (float, &pr->pr_edict_area[nextthink]) = time; + PR_PTR (float, &pr->pr_edict_area[frame]) = OPA(float); + PR_PTR (func, &pr->pr_edict_area[think]) = OPB(func); } break; case OP_STATE_F_v6p: @@ -1563,9 +1552,9 @@ op_call: int frame = pr->fields.frame + self; int think = pr->fields.think + self; float time = *pr->globals.ftime + OPC(float); - pr->pr_edict_area[nextthink].float_var = time; - pr->pr_edict_area[frame].float_var = OPA(float); - pr->pr_edict_area[think].func_var = OPB(func); + PR_PTR (float, &pr->pr_edict_area[nextthink]) = time; + PR_PTR (float, &pr->pr_edict_area[frame]) = OPA(float); + PR_PTR (func, &pr->pr_edict_area[think]) = OPB(func); } break; case OP_ADD_I_v6p: @@ -1748,8 +1737,7 @@ op_call: OPC(float) = OPA(double) < OPB(double); break; case OP_NOT_D_v6p: - OPC(int) = (op_a[0].int_var - || (op_a[1].int_var & ~0x80000000u)); + OPC(int) = (op_a[0].value || (op_a[1].value & ~0x80000000u)); break; case OP_EQ_D_v6p: OPC(int) = OPA(double) == OPB(double); @@ -1783,17 +1771,17 @@ op_call: default: PR_RunError (pr, "Bad opcode %i", st->op & ~OP_BREAK); } - if (pr->watch && pr->watch->int_var != old_val.int_var) { + if (pr->watch && pr->watch->value != old_val.value) { if (!pr->wp_conditional - || pr->watch->int_var == pr->wp_val.int_var) { + || pr->watch->value == pr->wp_val.value) { if (pr->debug_handler) { pr->debug_handler (prd_watchpoint, 0, pr->debug_data); } else { PR_RunError (pr, "watchpoint hit: %d -> %d", - old_val.int_var, pr->watch->int_var); + old_val.value, pr->watch->value); } } - old_val.int_var = pr->watch->int_var; + old_val.value = pr->watch->value; } } exit_program: @@ -1877,7 +1865,7 @@ pr_jump_mode (progs_t *pr, const dstatement_t *st, int jump_ind) break; case 1: // variable indexed array: a + *b (only +ve) - jump_offs = (op_a + OPB(uint))->uint_var; + jump_offs = PR_PTR (uint, op_a + OPB(uint)); break; case 2: // constant indexed pointer: *a + b (supports -ve offset) @@ -1963,7 +1951,7 @@ pr_with (progs_t *pr, const dstatement_t *st) case 4: // hard-0 base - pr->pr_bases[st->c & 3] = pr->pr_globals[st->b].pointer_var; + pr->pr_bases[st->c & 3] = G_POINTER (pr, st->b);; return; case 5: pr->pr_bases[st->c & 3] = OPB(ptr); @@ -2571,7 +2559,7 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth) case OP_CALL_C: case OP_CALL_D: mm = pr_call_mode (pr, st, st_op - OP_CALL_B + 1); - function = mm->func_var; + function = PR_PTR (func, mm); pr->pr_argc = 0; // op_c specifies the location for the return value if any pr->pr_xfunction->profile += profile - startprofile; @@ -2714,9 +2702,9 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth) int frame = pr->fields.frame + self; int think = pr->fields.think + self; float time = *pr->globals.ftime + 0.1; - pr->pr_edict_area[nextthink].float_var = time; - pr->pr_edict_area[frame].float_var = OPA(float); - pr->pr_edict_area[think].func_var = op_b->func_var; + PR_PTR (float, &pr->pr_edict_area[nextthink]) = time; + PR_PTR (float, &pr->pr_edict_area[frame]) = OPA(float); + PR_PTR (func, &pr->pr_edict_area[think]) = OPB(func); } break; OP_cmp_T (GE, U, long, lvec2, lvec4, >=, ulong, ulvec2, ulvec4); @@ -2736,9 +2724,9 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth) int frame = pr->fields.frame + self; int think = pr->fields.think + self; float time = *pr->globals.ftime + OPC(float); - pr->pr_edict_area[nextthink].float_var = time; - pr->pr_edict_area[frame].float_var = OPA(float); - pr->pr_edict_area[think].func_var = op_b->func_var; + PR_PTR (float, &pr->pr_edict_area[nextthink]) = time; + PR_PTR (float, &pr->pr_edict_area[frame]) = OPA(float); + PR_PTR (func, &pr->pr_edict_area[think]) = OPB(func); } break; // 1 1110 @@ -2768,9 +2756,9 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth) int frame = pr->fields.frame + self; int think = pr->fields.think + self; double time = *pr->globals.dtime + 0.1; - *(double *) (&pr->pr_edict_area[nextthink]) = time; - pr->pr_edict_area[frame].int_var = OPA(int); - pr->pr_edict_area[think].func_var = op_b->func_var; + PR_PTR (double, &pr->pr_edict_area[nextthink]) = time; + PR_PTR (int, &pr->pr_edict_area[frame]) = OPA(int); + PR_PTR (func, &pr->pr_edict_area[think]) = OPB(func); } break; OP_cmp_T (LE, U, long, lvec2, lvec4, <=, ulong, ulvec2, ulvec4); @@ -2799,9 +2787,9 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth) int frame = pr->fields.frame + self; int think = pr->fields.think + self; double time = *pr->globals.dtime + OPC(double); - *(double *) (&pr->pr_edict_area[nextthink]) = time; - pr->pr_edict_area[frame].int_var = OPA(int); - pr->pr_edict_area[think].func_var = op_b->func_var; + PR_PTR (double, &pr->pr_edict_area[nextthink]) = time; + PR_PTR (int, &pr->pr_edict_area[frame]) = OPA(int); + PR_PTR (func, &pr->pr_edict_area[think]) = OPB(func); } break; // 1 1111 @@ -2810,7 +2798,7 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth) case OP_LEA_C: case OP_LEA_D: mm = pr_address_mode (pr, st, (st_op - OP_LEA_A)); - op_c->pointer_var = mm - pr->pr_globals; + OPC(ptr) = mm - pr->pr_globals; break; case OP_QV4MUL_F: OPC(vec4) = qvmulf (OPA(vec4), OPB(vec4)); @@ -2862,17 +2850,17 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth) default: PR_RunError (pr, "Bad opcode o%03o", st->op & OP_MASK); } - if (pr->watch && pr->watch->int_var != old_val.int_var) { + if (pr->watch && pr->watch->value != old_val.value) { if (!pr->wp_conditional - || pr->watch->int_var == pr->wp_val.int_var) { + || pr->watch->value == pr->wp_val.value) { if (pr->debug_handler) { pr->debug_handler (prd_watchpoint, 0, pr->debug_data); } else { PR_RunError (pr, "watchpoint hit: %d -> %d", - old_val.int_var, pr->watch->int_var); + old_val.value, pr->watch->value); } } - old_val.int_var = pr->watch->int_var; + old_val.value = pr->watch->value; } } exit_program: diff --git a/libs/gamecode/pr_parse.c b/libs/gamecode/pr_parse.c index a1c198192..e43aef934 100644 --- a/libs/gamecode/pr_parse.c +++ b/libs/gamecode/pr_parse.c @@ -68,34 +68,34 @@ PR_UglyValueString (progs_t *pr, etype_t type, pr_type_t *val, dstring_t *line) switch (type) { case ev_string: - dsprintf (line, "%s", PR_GetString (pr, val->string_var)); + dsprintf (line, "%s", PR_GetString (pr, PR_PTR (string, val))); break; case ev_entity: dsprintf (line, "%d", - NUM_FOR_BAD_EDICT (pr, PROG_TO_EDICT (pr, val->entity_var))); + NUM_FOR_BAD_EDICT (pr, PROG_TO_EDICT (pr, PR_PTR (entity, val)))); break; case ev_func: - f = pr->pr_functions + val->func_var; + f = pr->pr_functions + PR_PTR (func, val); dsprintf (line, "%s", PR_GetString (pr, f->name)); break; case ev_field: - def = PR_FieldAtOfs (pr, val->int_var); + def = PR_FieldAtOfs (pr, PR_PTR (int, val)); dsprintf (line, "%s", PR_GetString (pr, def->name)); break; case ev_void: dstring_copystr (line, "void"); break; case ev_float: - dsprintf (line, "%.9g", val->float_var); + dsprintf (line, "%.9g", PR_PTR (float, val)); break; case ev_int: - dsprintf (line, "%d", val->int_var); + dsprintf (line, "%d", PR_PTR (int, val)); break; case ev_vector: - dsprintf (line, "%.9g %.9g %.9g", VectorExpand (&val->vector_var)); + dsprintf (line, "%.9g %.9g %.9g", VectorExpand (&PR_PTR (float, val))); break; case ev_quaternion: - dsprintf (line, "%.9g %.9g %.9g %.9g", QuatExpand (&val->quat_var)); + dsprintf (line, "%.9g %.9g %.9g %.9g", QuatExpand (&PR_PTR (float, val))); break; default: dsprintf (line, "bad type %i", type); @@ -132,7 +132,7 @@ ED_EntityDict (progs_t *pr, edict_t *ed) // if the value is still all 0, skip the field type = d->type & ~DEF_SAVEGLOBAL; for (j = 0; j < pr_type_size[type]; j++) - if (v[j].int_var) + if (v[j].value) break; if (j == pr_type_size[type]) continue; @@ -226,11 +226,11 @@ ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key, const char *s) switch (key->type & ~DEF_SAVEGLOBAL) { case ev_string: - d->string_var = ED_NewString (pr, s); + PR_PTR (string, d) = ED_NewString (pr, s); break; case ev_float: - d->float_var = atof (s); + PR_PTR (float, d) = atof (s); break; case ev_vector: @@ -241,14 +241,14 @@ ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key, const char *s) while (*v && *v != ' ') v++; *v = 0; - (&d->vector_var)[i] = atof (w); + (&PR_PTR (float, d))[i] = atof (w); w = v = v + 1; } free (string); break; case ev_entity: - d->entity_var = EDICT_TO_PROG (pr, EDICT_NUM (pr, atoi (s))); + PR_PTR (entity, d) = EDICT_TO_PROG (pr, EDICT_NUM (pr, atoi (s))); break; case ev_field: @@ -257,7 +257,7 @@ ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key, const char *s) Sys_Printf ("Can't find field %s\n", s); return false; } - d->int_var = G_INT (pr, def->ofs); + PR_PTR (int, d) = G_INT (pr, def->ofs); break; case ev_func: @@ -266,7 +266,7 @@ ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key, const char *s) Sys_Printf ("Can't find function %s\n", s); return false; } - d->func_var = func - pr->pr_functions; + PR_PTR (func, d) = func - pr->pr_functions; break; default: diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index eb0fcc6ab..7b70e12d4 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -860,9 +860,7 @@ fmt_append_item (fmt_state_t *state) } #undef P_var -#define P_var(p,n,t) (state->args[n]->t##_var) -#undef P_DOUBLE -#define P_DOUBLE(p,n) (*(double *) (state->args[n])) +#define P_var(p,n,t) PR_PTR (t, state->args[n]) /** State machine for PR_Sprintf * diff --git a/libs/gib/bi_gib.c b/libs/gib/bi_gib.c index c0a59178c..29d95930a 100644 --- a/libs/gib/bi_gib.c +++ b/libs/gib/bi_gib.c @@ -86,7 +86,8 @@ bi_gib_builtin_f (void) pr_list = PR_Zone_Malloc (builtin->pr, GIB_Argc() * sizeof (pr_type_t)); for (i = 0; i < GIB_Argc(); i++) - pr_list[i].int_var = PR_SetTempString (builtin->pr, GIB_Argv(i)); + PR_PTR (string, &pr_list[i]) = PR_SetTempString (builtin->pr, + GIB_Argv(i)); PR_RESET_PARAMS (builtin->pr); P_INT (builtin->pr, 0) = GIB_Argc(); diff --git a/libs/ruamoko/pr_cmds.c b/libs/ruamoko/pr_cmds.c index bf8d9c19c..63fc6c1e3 100644 --- a/libs/ruamoko/pr_cmds.c +++ b/libs/ruamoko/pr_cmds.c @@ -62,10 +62,10 @@ PF_VarString (progs_t *pr, int first, int argc) pr_type_t **argv = pr->pr_params; for (len = 0, i = first; i < argc; i++) - len += strlen (PR_GetString (pr, argv[i]->string_var)); + len += strlen (PR_GetString (pr, *(pr_string_t *) argv[i])); dst = out = Hunk_TempAlloc (0, len + 1); for (i = first; i < argc; i++) { - src = PR_GetString (pr, argv[i]->string_var); + src = PR_GetString (pr, PR_PTR (string, argv[i])); while (*src) *dst++ = *src++; } diff --git a/libs/ruamoko/rua_hash.c b/libs/ruamoko/rua_hash.c index 6f8b74547..63020060e 100644 --- a/libs/ruamoko/rua_hash.c +++ b/libs/ruamoko/rua_hash.c @@ -276,7 +276,7 @@ bi_Hash_FindList (progs_t *pr, void *_res) pr_list = PR_Zone_Malloc (pr, count * sizeof (pr_type_t)); // the hash tables stores progs pointers... for (count = 0, l = list; *l; l++) - pr_list[count++].int_var = (intptr_t) *l; + PR_PTR (ptr, &pr_list[count++]) = (intptr_t) *l; free (list); RETURN_POINTER (pr, pr_list); } @@ -296,7 +296,7 @@ bi_Hash_FindElementList (progs_t *pr, void *_res) pr_list = PR_Zone_Malloc (pr, count * sizeof (pr_type_t)); // the hash tables stores progs pointers... for (count = 0, l = list; *l; l++) - pr_list[count++].int_var = (intptr_t) *l; + PR_PTR (ptr, &pr_list[count++]) = (intptr_t) *l; free (list); RETURN_POINTER (pr, pr_list); } @@ -356,7 +356,7 @@ bi_Hash_GetList (progs_t *pr, void *_res) pr_list = PR_Zone_Malloc (pr, count * sizeof (pr_type_t)); // the hash tables stores progs pointers... for (count = 0, l = list; *l; l++) - pr_list[count++].int_var = (intptr_t) *l; + PR_PTR(ptr, &pr_list[count++]) = (intptr_t) *l; free (list); RETURN_POINTER (pr, pr_list); } diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index 510dff248..c7942c8e0 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -1507,25 +1507,27 @@ rua_obj_msg_sendv (progs_t *pr, void *data) RUA_CALL_END (pr, imp) } +#define RETAIN_COUNT(obj) PR_PTR (int, &(obj)[-1]) + static void rua_obj_increment_retaincount (progs_t *pr, void *data) { pr_type_t *obj = &P_STRUCT (pr, pr_type_t, 0); - R_INT (pr) = ++(*--obj).int_var; + R_INT (pr) = ++RETAIN_COUNT (obj); } static void rua_obj_decrement_retaincount (progs_t *pr, void *data) { pr_type_t *obj = &P_STRUCT (pr, pr_type_t, 0); - R_INT (pr) = --(*--obj).int_var; + R_INT (pr) = --RETAIN_COUNT (obj); } static void rua_obj_get_retaincount (progs_t *pr, void *data) { pr_type_t *obj = &P_STRUCT (pr, pr_type_t, 0); - R_INT (pr) = (*--obj).int_var; + R_INT (pr) = RETAIN_COUNT (obj); } static void diff --git a/nq/include/sv_progs.h b/nq/include/sv_progs.h index 4a09f1c5a..3849adf07 100644 --- a/nq/include/sv_progs.h +++ b/nq/include/sv_progs.h @@ -186,13 +186,9 @@ extern progs_t sv_pr_state; #define SVstring(e,f) SVFIELD (e, f, string) #define SVfunc(e,f) SVFIELD (e, f, func) #define SVentity(e,f) SVFIELD (e, f, entity) -#define SVvector(e,f) (&SVFIELD (e, f, vector)) +#define SVvector(e,f) (&SVFIELD (e, f, float)) #define SVint(e,f) SVFIELD (e, f, int) -#if TYPECHECK_PROGS -#define SVdouble(e,f) E_DOUBLE (e, PR_AccessField (&sv_pr_state, #f, ev_##t, __FILE__, __LINE__)) -#else -#define SVdouble(e,f) E_DOUBLE (e, sv_fields.f) -#endif +#define SVdouble(e,f) SVFIELD (e, f, double) typedef struct edict_leaf_s { struct edict_leaf_s *next; diff --git a/nq/source/sv_pr_cmds.c b/nq/source/sv_pr_cmds.c index 9984d97ff..b133b0bf4 100644 --- a/nq/source/sv_pr_cmds.c +++ b/nq/source/sv_pr_cmds.c @@ -1139,7 +1139,7 @@ PF_WriteBytes (progs_t *pr, void *data) } } for (i = 0; i < argc; i++) { - p = argv[i]->float_var; + p = PR_PTR (float, &argv[i]); MSG_WriteByte (msg, p); } } diff --git a/qw/include/sv_progs.h b/qw/include/sv_progs.h index 701475b7e..47e6b1198 100644 --- a/qw/include/sv_progs.h +++ b/qw/include/sv_progs.h @@ -193,13 +193,9 @@ extern progs_t sv_pr_state; #define SVstring(e,f) SVFIELD (e, f, string) #define SVfunc(e,f) SVFIELD (e, f, func) #define SVentity(e,f) SVFIELD (e, f, entity) -#define SVvector(e,f) (&SVFIELD (e, f, vector)) +#define SVvector(e,f) (&SVFIELD (e, f, float)) #define SVint(e,f) SVFIELD (e, f, int) -#if TYPECHECK_PROGS -#define SVdouble(e,f) E_DOUBLE (e, PR_AccessField (&sv_pr_state, #f, ev_##t, __FILE__, __LINE__)) -#else -#define SVdouble(e,f) E_DOUBLE (e, sv_fields.f) -#endif +#define SVdouble(e,f) SVFIELD (e, f, double) typedef struct edict_leaf_s { struct edict_leaf_s *next; diff --git a/qw/source/sv_pr_cmds.c b/qw/source/sv_pr_cmds.c index 103b0a3a3..fe892ea7c 100644 --- a/qw/source/sv_pr_cmds.c +++ b/qw/source/sv_pr_cmds.c @@ -1130,7 +1130,7 @@ PF_WriteBytes (progs_t *pr, void *data) } } for (i = 0; i < argc; i++) { - p = argv[i]->float_var; + p = PR_PTR (float, argv[i]); buf[i] = p; } diff --git a/qw/source/sv_progs.c b/qw/source/sv_progs.c index 345efc945..23a9c4061 100644 --- a/qw/source/sv_progs.c +++ b/qw/source/sv_progs.c @@ -181,16 +181,16 @@ static void free_edict (progs_t *pr, edict_t *ent) { if (sv_old_entity_free) { - E_fld (ent, sv_fields.model).entity_var = 0; - E_fld (ent, sv_fields.takedamage).float_var = 0; - E_fld (ent, sv_fields.modelindex).float_var = 0; - E_fld (ent, sv_fields.colormap).float_var = 0; - E_fld (ent, sv_fields.skin).float_var = 0; - E_fld (ent, sv_fields.frame).float_var = 0; - E_fld (ent, sv_fields.nextthink).float_var = -1; - E_fld (ent, sv_fields.solid).float_var = 0; - memset (&E_fld (ent, sv_fields.origin).vector_var, 0, 3*sizeof (float)); - memset (&E_fld (ent, sv_fields.angles).vector_var, 0, 3*sizeof (float)); + E_STRING (ent, sv_fields.model) = 0; + E_FLOAT (ent, sv_fields.takedamage) = 0; + E_FLOAT (ent, sv_fields.modelindex) = 0; + E_FLOAT (ent, sv_fields.colormap) = 0; + E_FLOAT (ent, sv_fields.skin) = 0; + E_FLOAT (ent, sv_fields.frame) = 0; + E_FLOAT (ent, sv_fields.nextthink) = -1; + E_FLOAT (ent, sv_fields.solid) = 0; + VectorZero (E_VECTOR (ent, sv_fields.origin)); + VectorZero (E_VECTOR (ent, sv_fields.angles)); } else { ED_ClearEdict (pr, ent, 0); } diff --git a/tools/qfcc/include/obj_file.h b/tools/qfcc/include/obj_file.h index e93c3013a..d1bc0a268 100644 --- a/tools/qfcc/include/obj_file.h +++ b/tools/qfcc/include/obj_file.h @@ -308,7 +308,7 @@ enum { \hideinitializer */ -#define QFO_var(q, s, t, o) ((q)->spaces[s].data[o].t##_var) +#define QFO_var(q, s, t, o) (*(pr_##t##_t *) &(q)->spaces[s].data[o]) /** Access a double variable in the object file. Can be assigned to. diff --git a/tools/qfcc/include/qfcc.h b/tools/qfcc/include/qfcc.h index b678cc5a4..a6384c91c 100644 --- a/tools/qfcc/include/qfcc.h +++ b/tools/qfcc/include/qfcc.h @@ -97,16 +97,17 @@ typedef struct pr_info_s { extern pr_info_t pr; #define GETSTR(s) (pr.strings->strings + (s)) -#define D_var(t, d) ((d)->space->data[(d)->offset].t##_var) -#define D_DOUBLE(d) (*(double *) ((d)->space->data + (d)->offset)) +#define D_PACKED(t,d) (*(t *) &(d)->space->data[(d)->offset]) +#define D_var(t, d) D_PACKED (pr_##t##_t, d) +#define D_DOUBLE(d) D_var (double, d) #define D_FLOAT(d) D_var (float, d) #define D_INT(d) D_var (int, d) -#define D_VECTOR(d) (&D_var (vector, d)) -#define D_QUAT(d) (&D_var (quat, d)) +#define D_VECTOR(d) (&D_var (float, d)) +#define D_QUAT(d) (&D_var (float, d)) #define D_STRING(d) D_var (string, d) #define D_GETSTR(d) GETSTR (D_STRING (d)) #define D_FUNCTION(d) D_var (func, d) -#define D_POINTER(t,d) ((t *)((d)->space->data + (d)->offset)) +#define D_POINTER(t,d) (&D_PACKED (t, d)) #define D_STRUCT(t,d) (*D_POINTER (t, d)) #define G_POINTER(s,t,o) ((t *)((s)->data + o)) diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 7a06a1730..4303eed60 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -401,7 +401,7 @@ init_elements (struct def_s *def, expr_t *eles) internal_error (c, "bogus expression type in init_elements()"); } if (c->e.value->lltype == ev_string) { - EMIT_STRING (def->space, g->string_var, + EMIT_STRING (def->space, *(pr_string_t *) g, c->e.value->v.string_val); } else { memcpy (g, &c->e.value->v, type_size (get_type (c)) * 4); @@ -636,7 +636,7 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, EMIT_STRING (sym->s.def->space, D_STRING (sym->s.def), v->v.string_val); } else { - memcpy (D_POINTER (void, sym->s.def), &v->v, + memcpy (D_POINTER (pr_type_t, sym->s.def), &v->v, type_size (sym->type) * sizeof (pr_type_t)); } } diff --git a/tools/qfcc/source/dump_globals.c b/tools/qfcc/source/dump_globals.c index d95c772cc..77ae2a2bc 100644 --- a/tools/qfcc/source/dump_globals.c +++ b/tools/qfcc/source/dump_globals.c @@ -327,7 +327,7 @@ qfo_globals (qfo_t *qfo) QFO_TYPESTR (qfo, def->type)); if (!(def->flags & QFOD_EXTERNAL) && qfo->spaces[space].data) printf (" %d", - qfo->spaces[space].data[def->offset].int_var); + qfo->spaces[space].data[def->offset].value); puts (""); } } diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index d7144ae27..863d56d64 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -433,7 +433,7 @@ qfo_byteswap_space (void *space, int size, qfos_type_t type) case qfos_type: case qfos_debug: for (val = (pr_type_t *) space, c = 0; c < size; c++, val++) - val->int_var = LittleLong (val->int_var); + val->value = LittleLong (val->value); break; } } diff --git a/tools/qfcc/source/qfcc.c b/tools/qfcc/source/qfcc.c index 5cc8c7aa4..98120e825 100644 --- a/tools/qfcc/source/qfcc.c +++ b/tools/qfcc/source/qfcc.c @@ -246,7 +246,7 @@ WriteProgs (dprograms_t *progs, int size) fielddefs[i].name = LittleLong (fielddefs[i].name); } for (i = 0; i < progs->globals.count; i++) - globals[i].int_var = LittleLong (globals[i].int_var); + globals[i].value = LittleLong (globals[i].value); if (!(h = Qopen (options.output_file, "wb"))) Sys_Error ("%s: %s\n", options.output_file, strerror(errno)); @@ -307,7 +307,7 @@ WriteSym (pr_debug_header_t *sym, int size) debug_defs[i].type_encoding = LittleLong (debug_defs[i].type_encoding); } for (i = 0; i < sym->debug_data_size; i++) { - debug_data[i].int_var = LittleLong (debug_data[i].int_var); + debug_data[i].value = LittleLong (debug_data[i].value); } if (!(h = Qopen (options.debug_file, "wb"))) diff --git a/tools/qfcc/source/reloc.c b/tools/qfcc/source/reloc.c index d235008d0..674be505f 100644 --- a/tools/qfcc/source/reloc.c +++ b/tools/qfcc/source/reloc.c @@ -73,7 +73,7 @@ static const char *reloc_name[] = { "rel_def_field_ofs", }; -#define RELOC(r) (r)->space->data[(r)->offset].int_var +#define RELOC(r) (r)->space->data[(r)->offset].value void relocate_refs (reloc_t *reloc, int offset) @@ -169,7 +169,7 @@ relocate_refs (reloc_t *reloc, int offset) case rel_def_field_ofs: //FIXME what is correct here? //RELOC (reloc) += pr.data->data[offset].int_var; - RELOC (reloc) += pr.near_data->data[offset].int_var; + RELOC (reloc) += PR_PTR (int, &pr.near_data->data[offset]); break; } reloc = reloc->next; diff --git a/tools/qfcc/source/struct.c b/tools/qfcc/source/struct.c index 4a9f64bce..318efb420 100644 --- a/tools/qfcc/source/struct.c +++ b/tools/qfcc/source/struct.c @@ -365,7 +365,7 @@ emit_structure (const char *name, int su, struct_def_t *defs, type_t *type, if (!defs[i].emit) { //FIXME relocs? arrays? structs? pr_type_t *val = (pr_type_t *) data; - memcpy (D_POINTER (void, &field_def), val, + memcpy (D_POINTER (pr_type_t, &field_def), val, type_size (field_def.type) * sizeof (pr_type_t)); data = &val[type_size (field_def.type)]; } else { diff --git a/tools/qfcc/source/value.c b/tools/qfcc/source/value.c index f96e5c720..c119473c9 100644 --- a/tools/qfcc/source/value.c +++ b/tools/qfcc/source/value.c @@ -614,7 +614,7 @@ emit_value (ex_value_t *value, def_t *def) break; } - memcpy (D_POINTER (void, cn), &val.v, 4 * type_size (type)); + memcpy (D_POINTER (pr_type_t, cn), &val.v, 4 * type_size (type)); make_def_imm (cn, tab, &val); From 71ae7aac4af47b561a2a1b2933037cdc2d505ae1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Apr 2022 17:19:47 +0900 Subject: [PATCH 02/34] [gamecode] Add macros for long and ulong --- include/QF/progs.h | 94 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/include/QF/progs.h b/include/QF/progs.h index 958bbd767..2e18fa3c5 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -476,6 +476,30 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define G_UINT(p,o) G_var (p, o, uint) +/** Access a long global. Can be assigned to. + + \par QC type: + \c long + \param p pointer to ::progs_t VM struct + \param o offset into global data space + \return long lvalue + + \hideinitializer +*/ +#define G_LONG(p,o) G_var (p, o, long) + +/** Access an unsigned long global. Can be assigned to. + + \par QC type: + \c ulong + \param p pointer to ::progs_t VM struct + \param o offset into global data space + \return unsigned long lvalue + + \hideinitializer +*/ +#define G_ULONG(p,o) G_var (p, o, ulong) + /** Access a vector global. Can be assigned to. \par QC type: @@ -715,6 +739,30 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define P_UINT(p,n) P_var (p, n, uint) +/** Access a long parameter. Can be assigned to. + + \par QC type: + \c long + \param p pointer to ::progs_t VM struct + \param n parameter number (0-7) + \return long lvalue + + \hideinitializer +*/ +#define P_LONG(p,n) P_var (p, n, long) + +/** Access an unsigned long parameter. Can be assigned to. + + \par QC type: + \c ulong + \param p pointer to ::progs_t VM struct + \param n parameter number (0-7) + \return unsigned long lvalue + + \hideinitializer +*/ +#define P_ULONG(p,n) P_var (p, n, ulong) + /** Access a vector parameter. Can be used any way a vec3_t variable can. \par QC type: @@ -928,6 +976,28 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define R_UINT(p) R_var (p, uint) +/** Access the VM function return value as a \c ::pr_long_t (AKA int32_t) + + \par QC type: + \c long + \param p pointer to ::progs_t VM struct + \return ::pr_long_t lvalue + + \hideinitializer +*/ +#define R_LONG(p) R_var (p, long) + +/** Access the VM function return value as a \c ::pr_ulong_t (AKA uint32_t) + + \par QC type: + \c ulong + \param p pointer to ::progs_t VM struct + \return ::pr_long_t lvalue + + \hideinitializer +*/ +#define R_ULONG(p) R_var (p, ulong) + /** Access the VM function return value as a \c ::vec3_t vector. \par QC type: @@ -1132,6 +1202,30 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define E_UINT(e,o) E_var (e, o, uint) +/** Access a long entity field. Can be assigned to. + + \par QC type: + \c long + \param e pointer to the entity + \param o field offset into entity data space + \return long lvalue + + \hideinitializer +*/ +#define E_LONG(e,o) E_var (e, o, long) + +/** Access an unsigned long entity field. Can be assigned to. + + \par QC type: + \c ulong + \param e pointer to the entity + \param o field offset into entity data space + \return unsigned long lvalue + + \hideinitializer +*/ +#define E_ULONG(e,o) E_var (e, o, ulong) + /** Access a vector entity field. Can be used any way a vec3_t variable can. \par QC type: From af2dfde37a192adc0e6f91f4f4778279faed49f4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Apr 2022 17:13:18 +0900 Subject: [PATCH 03/34] [gamecode] Support printing 64-bit integer types The 'l' modifier always means 64-bit, regardless of the underlying platform. As well, the 32-bit integer types are handled portably too. --- libs/gamecode/pr_strings.c | 66 +++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index 7b70e12d4..92129f7ad 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "QF/dstring.h" #include "QF/hash.h" @@ -60,10 +61,12 @@ typedef struct fmt_item_s { int precision; union { const char *string_var; - int integer_var; - unsigned uinteger_var; + pr_int_t int_var; + pr_uint_t uint_var; float float_var; double double_var; + pr_long_t long_var; + pr_ulong_t ulong_var; } data; struct fmt_item_s *next; } fmt_item_t; @@ -769,23 +772,35 @@ I_DoPrint (dstring_t *tmp, dstring_t *result, fmt_item_t *formatting) break; case 'c': dstring_appendstr (tmp, "c"); - PRINT (integer); + PRINT (int); break; case 'i': case 'd': - dstring_appendstr (tmp, "d"); - PRINT (integer); + if (current->flags & FMT_LONG) { + dstring_appendstr (tmp, PRId64); + PRINT (ulong); + } else { + dstring_appendstr (tmp, PRId32); + PRINT (uint); + } break; case 'x': - dstring_appendstr (tmp, "x"); - PRINT (integer); + if (current->flags & FMT_LONG) { + dstring_appendstr (tmp, PRIx64); + PRINT (ulong); + } else { + dstring_appendstr (tmp, PRIx32); + PRINT (uint); + } break; case 'u': - if (current->flags & FMT_HEX) - dstring_appendstr (tmp, "x"); - else - dstring_appendstr (tmp, "u"); - PRINT (uinteger); + if (current->flags & FMT_LONG) { + dstring_appendstr (tmp, PRIu64); + PRINT (ulong); + } else { + dstring_appendstr (tmp, PRIu32); + PRINT (uint); + } break; case 'f': dstring_appendstr (tmp, "f"); @@ -1019,6 +1034,12 @@ static void fmt_state_modifiers (fmt_state_t *state) { // no modifiers supported + if (state->c[0] == 'l' + && (state->c[1] == 'i' || state->c[1] == 'd' || state->c[1] == 'x' + || state->c[1] == 'u')) { + (*state->fi)->flags |= FMT_LONG; + state->c++; + } state->state = fmt_state_conversion; } @@ -1036,8 +1057,7 @@ fmt_state_conversion (fmt_state_t *state) case 'e': // entity (*state->fi)->type = 'i'; - (*state->fi)->data.integer_var = - P_EDICTNUM (pr, state->fmt_count); + (*state->fi)->data.int_var = P_EDICTNUM (pr, state->fmt_count); state->fmt_count++; fmt_append_item (state); @@ -1045,9 +1065,13 @@ fmt_state_conversion (fmt_state_t *state) case 'i': case 'd': case 'c': - // integer + // int (*state->fi)->type = conv; - (*state->fi)->data.integer_var = P_INT (pr, state->fmt_count); + if ((*state->fi)->flags & FMT_LONG) { + (*state->fi)->data.long_var = P_LONG (pr, state->fmt_count); + } else { + (*state->fi)->data.int_var = P_INT (pr, state->fmt_count); + } state->fmt_count++; fmt_append_item (state); @@ -1074,7 +1098,7 @@ fmt_state_conversion (fmt_state_t *state) // pointer (*state->fi)->flags |= FMT_ALTFORM; (*state->fi)->type = 'x'; - (*state->fi)->data.uinteger_var = P_UINT (pr, state->fmt_count); + (*state->fi)->data.uint_var = P_UINT (pr, state->fmt_count); state->fmt_count++; fmt_append_item (state); @@ -1132,9 +1156,13 @@ fmt_state_conversion (fmt_state_t *state) break; case 'u': case 'x': - // integer, unsigned or hex notation + // int, unsigned or hex notation (*state->fi)->type = conv; - (*state->fi)->data.uinteger_var = P_UINT (pr, state->fmt_count); + if ((*state->fi)->flags & FMT_LONG) { + (*state->fi)->data.ulong_var = P_ULONG (pr, state->fmt_count); + } else { + (*state->fi)->data.uint_var = P_UINT (pr, state->fmt_count); + } state->fmt_count++; fmt_append_item (state); From 8912c65029a77838ce791e31553744969022eabf Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Apr 2022 19:57:43 +0900 Subject: [PATCH 04/34] [qfcc] Indicate type width in type strings Makes for much more informative error messages for type mismatches (confusing when both sides look the same). --- tools/qfcc/include/type.h | 1 + tools/qfcc/source/def.c | 3 ++- tools/qfcc/source/expr_binary.c | 9 +++++---- tools/qfcc/source/type.c | 23 ++++++++++++++++++++++- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 63fb194e3..156189d33 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -166,6 +166,7 @@ type_t *alias_type (type_t *type, type_t *alias_chain, const char *name); const type_t *unalias_type (const type_t *type) __attribute__((pure)); const type_t *dereference_type (const type_t *type) __attribute__((pure)); void print_type_str (struct dstring_s *str, const type_t *type); +const char *get_type_string (const type_t *type); void print_type (const type_t *type); void dump_dot_type (void *t, const char *filename); const char *encode_params (const type_t *type); diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 4303eed60..b5d63177a 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -596,7 +596,8 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, } init_type = get_type (init); if (!type_assignable (sym->type, init_type)) { - error (init, "type mismatch in initializer"); + error (init, "type mismatch in initializer: %s = %s", + get_type_string (sym->type), get_type_string (init_type)); return; } if (storage == sc_local && local_expr) { diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index 6c792a1de..b2ac9eece 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -828,11 +828,12 @@ entity_compare (int op, expr_t *e1, expr_t *e2) static expr_t * invalid_binary_expr (int op, expr_t *e1, expr_t *e2) { - etype_t t1, t2; - t1 = extract_type (e1); - t2 = extract_type (e2); + type_t *t1, *t2; + t1 = get_type (e1); + t2 = get_type (e2); return error (e1, "invalid binary expression: %s %s %s", - pr_type_name[t1], get_op_string (op), pr_type_name[t2]); + get_type_string (t1), get_op_string (op), + get_type_string (t2)); } static expr_t * diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index a695e9f50..0387f862b 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -711,7 +711,9 @@ print_type_str (dstring_t *str, const type_t *type) case ev_short: case ev_ushort: case ev_double: - dasprintf (str, " %s", pr_type_name[type->type]); + dasprintf (str, " %s%s", pr_type_name[type->type], + type->width > 1 ? va (0, "{%d}", type->width) + : ""); return; case ev_invalid: case ev_type_count: @@ -722,6 +724,25 @@ print_type_str (dstring_t *str, const type_t *type) internal_error (0, "bad type meta:type %d:%d", type->meta, type->type); } +const char * +get_type_string (const type_t *type) +{ + static dstring_t *type_str[8]; + static int str_index; + + if (!type_str[str_index]) { + type_str[str_index] = dstring_newstr (); + } + dstring_clearstr (type_str[str_index]); + print_type_str (type_str[str_index], type); + const char *str = type_str[str_index++]->str; + str_index %= sizeof (type_str) / sizeof (type_str[0]); + while (*str == ' ') { + str++; + } + return str; +} + void print_type (const type_t *type) { From 67bdbc6f7a922b2ba4269fed5106659abbddad65 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 27 Apr 2022 11:25:33 +0900 Subject: [PATCH 05/34] [qfcc] Split out vector expression code I plan on extending it for the new vector types and expr.c is just too big to work in nicely. --- tools/qfcc/source/Makemodule.am | 1 + tools/qfcc/source/expr.c | 155 ----------------------- tools/qfcc/source/expr_vector.c | 216 ++++++++++++++++++++++++++++++++ 3 files changed, 217 insertions(+), 155 deletions(-) create mode 100644 tools/qfcc/source/expr_vector.c diff --git a/tools/qfcc/source/Makemodule.am b/tools/qfcc/source/Makemodule.am index d7d85e597..0406cea3e 100644 --- a/tools/qfcc/source/Makemodule.am +++ b/tools/qfcc/source/Makemodule.am @@ -30,6 +30,7 @@ qfcc_SOURCES = \ tools/qfcc/source/expr_bool.c \ tools/qfcc/source/expr_compound.c \ tools/qfcc/source/expr_obj.c \ + tools/qfcc/source/expr_vector.c \ tools/qfcc/source/flow.c \ tools/qfcc/source/function.c \ tools/qfcc/source/grab.c \ diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 746a94f03..8033d6435 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -42,7 +42,6 @@ #include "QF/alloc.h" #include "QF/dstring.h" #include "QF/mathlib.h" -#include "QF/sys.h" #include "QF/va.h" #include "tools/qfcc/include/qfcc.h" @@ -127,88 +126,6 @@ convert: e->e = new->e; } -expr_t * -convert_vector (expr_t *e) -{ - float val[4]; - - if (e->type != ex_vector) - return e; - if (is_vector(e->e.vector.type)) { - // guaranteed to have three elements - expr_t *x = e->e.vector.list; - expr_t *y = x->next; - expr_t *z = y->next; - x = fold_constants (cast_expr (&type_float, x)); - y = fold_constants (cast_expr (&type_float, y)); - z = fold_constants (cast_expr (&type_float, z)); - if (is_constant (x) && is_constant (y) && is_constant (z)) { - val[0] = expr_float(x); - val[1] = expr_float(y); - val[2] = expr_float(z); - return new_vector_expr (val); - } - // at least one of x, y, z is not constant, so rebuild the - // list incase any of them are new expressions - z->next = 0; - y->next = z; - x->next = y; - e->e.vector.list = x; - return e; - } - if (is_quaternion(e->e.vector.type)) { - // guaranteed to have two or four elements - if (e->e.vector.list->next->next) { - // four vals: x, y, z, w - expr_t *x = e->e.vector.list; - expr_t *y = x->next; - expr_t *z = y->next; - expr_t *w = z->next; - x = fold_constants (cast_expr (&type_float, x)); - y = fold_constants (cast_expr (&type_float, y)); - z = fold_constants (cast_expr (&type_float, z)); - w = fold_constants (cast_expr (&type_float, w)); - if (is_constant (x) && is_constant (y) && is_constant (z) - && is_constant (w)) { - val[0] = expr_float(x); - val[1] = expr_float(y); - val[2] = expr_float(z); - val[3] = expr_float(w); - return new_quaternion_expr (val); - } - // at least one of x, y, z, w is not constant, so rebuild the - // list incase any of them are new expressions - w->next = 0; - z->next = w; - y->next = z; - x->next = y; - e->e.vector.list = x; - return e; - } else { - // v, s - expr_t *v = e->e.vector.list; - expr_t *s = v->next; - - v = convert_vector (v); - s = fold_constants (cast_expr (&type_float, s)); - if (is_constant (v) && is_constant (s)) { - memcpy (val, expr_vector (v), 3 * sizeof (float)); - val[3] = expr_float (s); - return new_quaternion_expr (val); - } - // Either v or s is not constant, so can't convert to a quaternion - // constant. - // Rebuild the list in case v or s is a new expression - // the list will always be v, s - s->next = 0; - v->next = s; - e->e.vector.list = v; - return e; - } - } - internal_error (e, "bogus vector expression"); -} - type_t * get_type (expr_t *e) { @@ -827,78 +744,6 @@ new_vector_expr (const float *vector_val) return e; } -expr_t * -new_vector_list (expr_t *e) -{ - expr_t *t; - int count; - type_t *type = &type_vector; - expr_t *vec; - - e = reverse_expr_list (e); // put the elements in the right order - for (t = e, count = 0; t; t = t->next) - count++; - switch (count) { - case 4: - type = &type_quaternion; - case 3: - // quaternion or vector. all expressions must be compatible with - // a float (ie, a scalar) - for (t = e; t; t = t->next) { - if (t->type == ex_error) { - return t; - } - if (!is_scalar (get_type (t))) { - return error (t, "invalid type for vector element"); - } - } - vec = new_expr (); - vec->type = ex_vector; - vec->e.vector.type = type; - vec->e.vector.list = e; - break; - case 2: - if (e->type == ex_error || e->next->type == ex_error) { - return e; - } - if (is_scalar (get_type (e)) && is_scalar (get_type (e->next))) { - // scalar, scalar - // expand [x, y] to [x, y, 0] - e->next->next = new_float_expr (0); - vec = new_expr (); - vec->type = ex_vector; - vec->e.vector.type = type; - vec->e.vector.list = e; - break; - } - // quaternion. either scalar, vector or vector, scalar - if (is_scalar (get_type (e)) - && is_vector (get_type (e->next))) { - // scalar, vector - // swap expressions - t = e; - e = e->next; - e->next = t; - t->next = 0; - } else if (is_vector (get_type (e)) - && is_scalar (get_type (e->next))) { - // vector, scalar - // do nothing - } else { - return error (t, "invalid types for vector elements"); - } - // v, s - vec = new_expr (); - vec->type = ex_vector; - vec->e.vector.type = &type_quaternion; - vec->e.vector.list = e; - break; - default: - return error (e, "invalid number of elements in vector exprssion"); - } - return vec; -} - expr_t * new_entity_expr (int entity_val) { diff --git a/tools/qfcc/source/expr_vector.c b/tools/qfcc/source/expr_vector.c new file mode 100644 index 000000000..8b7cc1495 --- /dev/null +++ b/tools/qfcc/source/expr_vector.c @@ -0,0 +1,216 @@ +/* + expr_vector.c + + vector expressions + + Copyright (C) 2022 Bill Currie + + Author: Bill Currie + Date: 2022/04/27 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "QF/alloc.h" +#include "QF/dstring.h" +#include "QF/mathlib.h" +#include "QF/sys.h" +#include "QF/va.h" + +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/idstuff.h" +#include "tools/qfcc/include/method.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/shared.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/struct.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" + +#include "tools/qfcc/source/qc-parse.h" + +expr_t * +convert_vector (expr_t *e) +{ + float val[4]; + + if (e->type != ex_vector) + return e; + if (is_vector(e->e.vector.type)) { + // guaranteed to have three elements + expr_t *x = e->e.vector.list; + expr_t *y = x->next; + expr_t *z = y->next; + x = fold_constants (cast_expr (&type_float, x)); + y = fold_constants (cast_expr (&type_float, y)); + z = fold_constants (cast_expr (&type_float, z)); + if (is_constant (x) && is_constant (y) && is_constant (z)) { + val[0] = expr_float(x); + val[1] = expr_float(y); + val[2] = expr_float(z); + return new_vector_expr (val); + } + // at least one of x, y, z is not constant, so rebuild the + // list incase any of them are new expressions + z->next = 0; + y->next = z; + x->next = y; + e->e.vector.list = x; + return e; + } + if (is_quaternion(e->e.vector.type)) { + // guaranteed to have two or four elements + if (e->e.vector.list->next->next) { + // four vals: x, y, z, w + expr_t *x = e->e.vector.list; + expr_t *y = x->next; + expr_t *z = y->next; + expr_t *w = z->next; + x = fold_constants (cast_expr (&type_float, x)); + y = fold_constants (cast_expr (&type_float, y)); + z = fold_constants (cast_expr (&type_float, z)); + w = fold_constants (cast_expr (&type_float, w)); + if (is_constant (x) && is_constant (y) && is_constant (z) + && is_constant (w)) { + val[0] = expr_float(x); + val[1] = expr_float(y); + val[2] = expr_float(z); + val[3] = expr_float(w); + return new_quaternion_expr (val); + } + // at least one of x, y, z, w is not constant, so rebuild the + // list incase any of them are new expressions + w->next = 0; + z->next = w; + y->next = z; + x->next = y; + e->e.vector.list = x; + return e; + } else { + // v, s + expr_t *v = e->e.vector.list; + expr_t *s = v->next; + + v = convert_vector (v); + s = fold_constants (cast_expr (&type_float, s)); + if (is_constant (v) && is_constant (s)) { + memcpy (val, expr_vector (v), 3 * sizeof (float)); + val[3] = expr_float (s); + return new_quaternion_expr (val); + } + // Either v or s is not constant, so can't convert to a quaternion + // constant. + // Rebuild the list in case v or s is a new expression + // the list will always be v, s + s->next = 0; + v->next = s; + e->e.vector.list = v; + return e; + } + } + internal_error (e, "bogus vector expression"); +} + +expr_t * +new_vector_list (expr_t *e) +{ + expr_t *t; + int count; + type_t *type = &type_vector; + expr_t *vec; + + e = reverse_expr_list (e); // put the elements in the right order + for (t = e, count = 0; t; t = t->next) + count++; + switch (count) { + case 4: + type = &type_quaternion; + case 3: + // quaternion or vector. all expressions must be compatible with + // a float (ie, a scalar) + for (t = e; t; t = t->next) { + if (t->type == ex_error) { + return t; + } + if (!is_scalar (get_type (t))) { + return error (t, "invalid type for vector element"); + } + } + vec = new_expr (); + vec->type = ex_vector; + vec->e.vector.type = type; + vec->e.vector.list = e; + break; + case 2: + if (e->type == ex_error || e->next->type == ex_error) { + return e; + } + if (is_scalar (get_type (e)) && is_scalar (get_type (e->next))) { + // scalar, scalar + // expand [x, y] to [x, y, 0] + e->next->next = new_float_expr (0); + vec = new_expr (); + vec->type = ex_vector; + vec->e.vector.type = type; + vec->e.vector.list = e; + break; + } + // quaternion. either scalar, vector or vector, scalar + if (is_scalar (get_type (e)) + && is_vector (get_type (e->next))) { + // scalar, vector + // swap expressions + t = e; + e = e->next; + e->next = t; + t->next = 0; + } else if (is_vector (get_type (e)) + && is_scalar (get_type (e->next))) { + // vector, scalar + // do nothing + } else { + return error (t, "invalid types for vector elements"); + } + // v, s + vec = new_expr (); + vec->type = ex_vector; + vec->e.vector.type = &type_quaternion; + vec->e.vector.list = e; + break; + default: + return error (e, "invalid number of elements in vector exprssion"); + } + return vec; +} From 73d6e97e7b86a257ad1656e3441ba0dcea942ea5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 27 Apr 2022 18:07:30 +0900 Subject: [PATCH 06/34] [qwaq] Ensure PR_Init_Cvars is called only once Registering the same cvar more than once is currently a fatal error, but qwaq was calling PR_Init_Cvars for each thread. Oops. --- ruamoko/qwaq/builtins/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruamoko/qwaq/builtins/main.c b/ruamoko/qwaq/builtins/main.c index b4954a0bb..02e703822 100644 --- a/ruamoko/qwaq/builtins/main.c +++ b/ruamoko/qwaq/builtins/main.c @@ -149,6 +149,7 @@ init_qf (void) //Cvar_Set (developer, "1"); Memory_Init (Sys_Alloc (8 * 1024 * 1024), 8 * 1024 * 1024); + PR_Init_Cvars (); } static void @@ -208,7 +209,6 @@ create_progs (qwaq_thread_t *thread) pr->no_exec_limit = 1; pr->hashlink_freelist = &thread->hashlink_freelist; - PR_Init_Cvars (); pr_debug = 2; pr_boundscheck = 0; PR_Init (pr); From 875c9bde7c169aebc5fb4ba7b8169662cbf0298c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 27 Apr 2022 18:10:40 +0900 Subject: [PATCH 07/34] [gamecode] Print operand widths when not 1 The widths for all three operands are printed if any is greater than 1. Makes figuring out which instruction is executing a little easier. --- libs/gamecode/pr_debug.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 2f3d4905f..01d9f6ebe 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -1490,6 +1490,7 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) int dump_code = contents & 2; const char *fmt; const char *mnemonic; + const char *width = ""; dfunction_t *call_func = 0; pr_def_t *param_def = 0; pr_auxfunction_t *aux_func = 0; @@ -1558,13 +1559,15 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) print_raw_op (pr, s->a, PR_BASE_IND (s->op, A), op_type[0], op_width[0]), print_raw_op (pr, s->b, PR_BASE_IND (s->op, B), - op_type[0], op_width[0]), + op_type[1], op_width[1]), print_raw_op (pr, s->c, PR_BASE_IND (s->op, C), - op_type[0], op_width[0])); + op_type[2], op_width[2])); } + } else if (op_width[0] > 1 || op_width[1] > 1 || op_width[2] > 1) { + width = va (res->va, "{%d,%d,%d}", VectorExpand (op_width)); } - dasprintf (res->line, "%s ", mnemonic); + dasprintf (res->line, "%s%s ", mnemonic, width); while (*fmt) { if (*fmt == '%') { From c120bf294016c73f2770c3f8a5d564770b63fb7a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 27 Apr 2022 21:24:46 +0900 Subject: [PATCH 08/34] [qfcc] Add functions to store and load values This makes working with constant expressions much less tedious, especially when the relevant code needs to work with many types. --- tools/qfcc/include/value.h | 5 +++++ tools/qfcc/source/value.c | 39 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/tools/qfcc/include/value.h b/tools/qfcc/include/value.h index 21e10f43d..5ff0fa925 100644 --- a/tools/qfcc/include/value.h +++ b/tools/qfcc/include/value.h @@ -40,6 +40,7 @@ struct def_s; struct ex_value_s; struct tempop_s; struct type_s; +struct pr_type_s; struct ex_value_s *new_string_val (const char *string_val); struct ex_value_s *new_double_val (double double_val); @@ -57,6 +58,10 @@ struct ex_value_s *new_int_val (int int_val); struct ex_value_s *new_uint_val (int uint_val); struct ex_value_s *new_short_val (short short_val); struct ex_value_s *new_nil_val (struct type_s *type); +struct ex_value_s *new_type_value (const struct type_s *type, + const struct pr_type_s *data); +void value_store (pr_type_t *dst, const struct type_s *dstType, + const struct expr_s *src); struct ex_value_s *convert_value (struct ex_value_s *value, struct type_s *type); diff --git a/tools/qfcc/source/value.c b/tools/qfcc/source/value.c index c119473c9..a88af6ea3 100644 --- a/tools/qfcc/source/value.c +++ b/tools/qfcc/source/value.c @@ -269,6 +269,45 @@ new_nil_val (type_t *type) return find_value (&val); } +ex_value_t * +new_type_value (const type_t *type, const pr_type_t *data) +{ + size_t typeSize = type_size (type) * sizeof (pr_type_t); + ex_value_t val = {}; + set_val_type (&val, (type_t *) type);//FIXME cast + memcpy (&val.v, data, typeSize); + return find_value (&val); +} + +void +value_store (pr_type_t *dst, const type_t *dstType, const expr_t *src) +{ + size_t dstSize = type_size (dstType) * sizeof (pr_type_t); + + if (src->type == ex_nil) { + memset (dst, 0, dstSize); + return; + } + if (src->type == ex_symbol && src->e.symbol->sy_type == sy_var) { + // initialized global def treated as a constant + // from the tests in cast_expr, the def is known to be constant + def_t *def = src->e.symbol->s.def; + memcpy (dst, &D_PACKED (pr_type_t, def), dstSize); + return; + } + ex_value_t *val = 0; + if (src->type == ex_value) { + val = src->e.value; + } + if (src->type == ex_symbol && src->e.symbol->sy_type == sy_const) { + val = src->e.symbol->s.value; + } + if (!val) { + internal_error (src, "unexpected constant expression type"); + } + memcpy (dst, &val->v, dstSize); +} + static hashtab_t *string_imm_defs; static hashtab_t *float_imm_defs; static hashtab_t *vector_imm_defs; From ae0b3a58706ccdc9e7453cfc0bdf6a5bb1b20b2b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 27 Apr 2022 21:32:41 +0900 Subject: [PATCH 09/34] [qfcc] Add some utility functions for working with vector types Finding vector types from base type and width, and getting the base type for a vector type, as well as basic promotion rules for math types. --- tools/qfcc/include/type.h | 5 +++ tools/qfcc/source/statements.c | 17 ++------ tools/qfcc/source/type.c | 77 ++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 14 deletions(-) diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 156189d33..69ca4bc4b 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -160,6 +160,8 @@ type_t *find_type (type_t *new); void new_typedef (const char *name, type_t *type); type_t *field_type (type_t *aux); type_t *pointer_type (type_t *aux); +type_t *vector_type (const type_t *ele_type, int width) __attribute__((pure)); +type_t *base_type (const type_t *vec_type) __attribute__((pure)); type_t *array_type (type_t *aux, int size); type_t *based_array_type (type_t *aux, int base, int top); type_t *alias_type (type_t *type, type_t *alias_chain, const char *name); @@ -187,6 +189,7 @@ int is_array (const type_t *type) __attribute__((pure)); int is_structural (const type_t *type) __attribute__((pure)); int type_compatible (const type_t *dst, const type_t *src) __attribute__((pure)); int type_assignable (const type_t *dst, const type_t *src); +int type_promotes (const type_t *dst, const type_t *src) __attribute__((pure)); int type_same (const type_t *dst, const type_t *src) __attribute__((pure)); int type_size (const type_t *type) __attribute__((pure)); int type_width (const type_t *type) __attribute__((pure)); @@ -197,5 +200,7 @@ void chain_initial_types (void); void clear_typedefs (void); extern type_t *ev_types[]; +extern int type_cast_map[]; +#define TYPE_CAST_CODE(from, to, width) (((width) << 6) | ((from) << 3) | (to)) #endif//__type_h diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index fda9e9a2e..7c7ad4d4b 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -1760,17 +1760,6 @@ expr_expr (sblock_t *sblock, expr_t *e, operand_t **op) return sblock; } -static int type_map[ev_type_count] = { - [ev_int] = 0, - [ev_float] = 1, - [ev_long] = 2, - [ev_double] = 3, - [ev_uint] = 4, - //[ev_bool32] = 5, - [ev_ulong] = 6, - //[ev_bool64] = 7, -}; - static sblock_t * expr_cast (sblock_t *sblock, expr_t *e, operand_t **op) { @@ -1786,10 +1775,10 @@ expr_cast (sblock_t *sblock, expr_t *e, operand_t **op) s = new_statement (st_expr, "conv", e); s->opa = src; if (options.code.progsversion == PROG_VERSION) { - int from = type_map[src_type->type]; - int to = type_map[type->type]; + int from = type_cast_map[src_type->type]; + int to = type_cast_map[type->type]; int width = type_width (src_type) - 1; - int conv = (width << 6) | (from << 3) | to; + int conv = TYPE_CAST_CODE (from, to, width); s->opb = short_operand (conv, e); } s->opc = *op; diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 0387f862b..f25cb6eba 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -89,6 +89,11 @@ type_t type_invalid = { }; #include "tools/qfcc/include/vec_types.h" +#define VEC_TYPE(type_name, base_type) &type_##type_name, +static type_t *vec_types[] = { +#include "tools/qfcc/include/vec_types.h" + 0 +}; type_t *type_nil; type_t *type_default; type_t *type_long_int; @@ -145,6 +150,17 @@ type_t *ev_types[ev_type_count] = { &type_invalid, }; +int type_cast_map[ev_type_count] = { + [ev_int] = 0, + [ev_float] = 1, + [ev_long] = 2, + [ev_double] = 3, + [ev_uint] = 4, + //[ev_bool32] = 5, + [ev_ulong] = 6, + //[ev_bool64] = 7, +}; + static type_t *types_freelist; etype_t @@ -524,6 +540,38 @@ pointer_type (type_t *aux) return new; } +type_t * +vector_type (const type_t *ele_type, int width) +{ + if (width == 1) { + for (type_t **t = ev_types; t - ev_types < ev_type_count; t++) { + if ((*t)->type == ele_type->type && (*t)->width == 1) { + return *t; + } + } + } + for (type_t **vtype = vec_types; *vtype; vtype++) { + if ((*vtype)->type == ele_type->type + && (*vtype)->width == width) { + return *vtype; + } + } + return 0; +} + +type_t * +base_type (const type_t *vec_type) +{ + if (!is_math (vec_type)) { + return 0; + } + // vec_type->type for quaternion and vector points back to itself + if (is_quaternion (vec_type) || is_vector (vec_type)) { + return &type_float; + } + return ev_types[vec_type->type]; +} + type_t * array_type (type_t *aux, int size) { @@ -1097,6 +1145,35 @@ type_assignable (const type_t *dst, const type_t *src) return 0; } +int +type_promotes (const type_t *dst, const type_t *src) +{ + dst = unalias_type (dst); + src = unalias_type (src); + // nothing promotes to int + if (is_int (dst)) { + return 0; + } + if (is_uint (dst) && is_int (src)) { + return 1; + } + if (is_long (dst) && (is_int (src) || is_uint (src))) { + return 1; + } + if (is_ulong (dst) && (is_int (src) || is_uint (src) || is_long (src))) { + return 1; + } + if (is_float (dst) && (is_int (src) || is_uint (src))) { + return 1; + } + //XXX what to do with (u)long<->float? + // everything promotes to double + if (is_double (dst)) { + return 1; + } + return 0; +} + int type_same (const type_t *dst, const type_t *src) { From 85d851572ffecf46b1a800229d013dd2e62d43d2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 27 Apr 2022 21:36:15 +0900 Subject: [PATCH 10/34] [qfcc] Implement constant casts for the new vector types Nicely, I was able to reuse the generated conversion code used by the progs engine to do the work in qfcc, just needed appropriate definitions for the operand macros, and to set up the conversion code. Helped greatly by the new value load/store functions. --- tools/qfcc/include/expr.h | 4 +- tools/qfcc/source/Makemodule.am | 1 + tools/qfcc/source/expr.c | 119 ++++--------------------- tools/qfcc/source/expr_cast.c | 148 ++++++++++++++++++++++++++++++++ 4 files changed, 170 insertions(+), 102 deletions(-) create mode 100644 tools/qfcc/source/expr_cast.c diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 2b3887ae1..3c2f2a555 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -205,6 +205,8 @@ typedef struct ex_value_s { unsigned uint_val; ///< unsigned int constant int16_t short_val; ///< short constant uint16_t ushort_val; ///< unsigned short constant +#define VEC_TYPE(type_name, base_type) pr_##type_name##_t type_name##_val; +#include "tools/qfcc/include/vec_types.h" } v; } ex_value_t; @@ -309,7 +311,6 @@ expr_t *type_mismatch (expr_t *e1, expr_t *e2, int op); expr_t *param_mismatch (expr_t *e, int param, const char *fn, struct type_s *t1, struct type_s *t2); -expr_t *cast_error (expr_t *e, struct type_s *t1, struct type_s *t2); expr_t *test_error (expr_t *e, struct type_s *t); extern expr_t *local_expr; @@ -640,6 +641,7 @@ unsigned expr_uint (expr_t *e) __attribute__((pure)); */ expr_t *new_short_expr (short short_val); short expr_short (expr_t *e) __attribute__((pure)); +unsigned short expr_ushort (expr_t *e) __attribute__((pure)); int expr_integral (expr_t *e) __attribute__((pure)); diff --git a/tools/qfcc/source/Makemodule.am b/tools/qfcc/source/Makemodule.am index 0406cea3e..a070fad67 100644 --- a/tools/qfcc/source/Makemodule.am +++ b/tools/qfcc/source/Makemodule.am @@ -28,6 +28,7 @@ qfcc_SOURCES = \ tools/qfcc/source/expr_assign.c \ tools/qfcc/source/expr_binary.c \ tools/qfcc/source/expr_bool.c \ + tools/qfcc/source/expr_cast.c \ tools/qfcc/source/expr_compound.c \ tools/qfcc/source/expr_obj.c \ tools/qfcc/source/expr_vector.c \ diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 8033d6435..388ab8e14 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -214,16 +214,9 @@ extract_type (expr_t *e) expr_t * type_mismatch (expr_t *e1, expr_t *e2, int op) { - dstring_t *t1 = dstring_newstr (); - dstring_t *t2 = dstring_newstr (); - - print_type_str (t1, get_type (e1)); - print_type_str (t2, get_type (e2)); - e1 = error (e1, "type mismatch: %s %s %s", - t1->str, get_op_string (op), t2->str); - dstring_delete (t1); - dstring_delete (t2); + get_type_string (get_type (e1)), get_op_string (op), + get_type_string (get_type (e2))); return e1; } @@ -243,21 +236,6 @@ param_mismatch (expr_t *e, int param, const char *fn, type_t *t1, type_t *t2) return e; } -expr_t * -cast_error (expr_t *e, type_t *t1, type_t *t2) -{ - dstring_t *s1 = dstring_newstr (); - dstring_t *s2 = dstring_newstr (); - - print_type_str (s1, t1); - print_type_str (s2, t2); - - e = error (e, "cannot cast from %s to %s", s1->str, s2->str); - dstring_delete (s1); - dstring_delete (s2); - return e; -} - expr_t * test_error (expr_t *e, type_t *t) { @@ -1145,6 +1123,22 @@ expr_short (expr_t *e) internal_error (e, "not a short constant"); } +unsigned short +expr_ushort (expr_t *e) +{ + if (e->type == ex_nil) { + return 0; + } + if (e->type == ex_value && e->e.value->lltype == ev_ushort) { + return e->e.value->v.ushort_val; + } + if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const + && e->e.symbol->type->type == ev_ushort) { + return e->e.symbol->s.value->v.ushort_val; + } + internal_error (e, "not a ushort constant"); +} + int is_integral_val (expr_t *e) { @@ -2872,83 +2866,6 @@ think_expr (symbol_t *think_sym) return new_symbol_expr (think_sym); } -expr_t * -cast_expr (type_t *dstType, expr_t *e) -{ - expr_t *c; - type_t *srcType; - - convert_name (e); - - if (e->type == ex_error) - return e; - - dstType = (type_t *) unalias_type (dstType); //FIXME cast - srcType = get_type (e); - - if (dstType == srcType) - return e; - - if ((dstType == type_default && is_enum (srcType)) - || (is_enum (dstType) && srcType == type_default)) - return e; - if ((is_ptr (dstType) && is_string (srcType)) - || (is_string (dstType) && is_ptr (srcType))) { - c = new_alias_expr (dstType, e); - return c; - } - if (!(is_ptr (dstType) && (is_ptr (srcType) || is_integral (srcType) - || is_array (srcType))) - && !(is_integral (dstType) && is_ptr (srcType)) - && !(is_func (dstType) && is_func (srcType)) - && !(is_scalar (dstType) && is_scalar (srcType))) { - return cast_error (e, srcType, dstType); - } - if (is_array (srcType)) { - return address_expr (e, dstType->t.fldptr.type); - } - if (is_constant (e) && is_scalar (dstType) && is_scalar (srcType)) { - ex_value_t *val = 0; - if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const) { - val = e->e.symbol->s.value; - } else if (e->type == ex_symbol - && e->e.symbol->sy_type == sy_var) { - // initialized global def treated as a constant - // from the tests above, the def is known to be constant - // and of one of the three storable scalar types - def_t *def = e->e.symbol->s.def; - if (is_float (def->type)) { - val = new_float_val (D_FLOAT (def)); - } else if (is_double (def->type)) { - val = new_double_val (D_DOUBLE (def)); - } else if (is_integral (def->type)) { - val = new_int_val (D_INT (def)); - } - } else if (e->type == ex_value) { - val = e->e.value; - } else if (e->type == ex_nil) { - convert_nil (e, dstType); - return e; - } - if (!val) - internal_error (e, "unexpected constant expression type"); - e->e.value = convert_value (val, dstType); - e->type = ex_value; - c = e; - } else if (is_integral (dstType) && is_integral (srcType)) { - c = new_alias_expr (dstType, e); - } else if (is_scalar (dstType) && is_scalar (srcType)) { - c = new_unary_expr ('C', e); - c->e.expr.type = dstType; - } else if (e->type == ex_uexpr && e->e.expr.op == '.') { - e->e.expr.type = dstType; - c = e; - } else { - c = new_alias_expr (dstType, e); - } - return c; -} - expr_t * encode_expr (type_t *type) { diff --git a/tools/qfcc/source/expr_cast.c b/tools/qfcc/source/expr_cast.c new file mode 100644 index 000000000..9ec9e9d1a --- /dev/null +++ b/tools/qfcc/source/expr_cast.c @@ -0,0 +1,148 @@ +/* + expr_cast.c + + expression casting + + Copyright (C) 2022 Bill Currie + + Author: Bill Currie + Date: 2022/04/27 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "QF/mathlib.h" + +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" + +static expr_t * +cast_error (expr_t *e, type_t *t1, type_t *t2) +{ + e = error (e, "cannot cast from %s to %s", get_type_string (t1), + get_type_string (t2)); + return e; +} + +static void +do_conversion (pr_type_t *dst_value, type_t *dstType, + pr_type_t *src_value, type_t *srcType, expr_t *expr) +{ + int from = type_cast_map[base_type (srcType)->type]; + int to = type_cast_map[base_type (dstType)->type]; + int width = type_width (srcType) - 1; + int conversion = TYPE_CAST_CODE (from, to, width); +#define OPA(type) (*((pr_##type##_t *) (src_value))) +#define OPC(type) (*((pr_##type##_t *) (dst_value))) + switch (conversion) { +#include "libs/gamecode/pr_convert.cinc" + default: + internal_error (expr, "invalid conversion code: %04o", conversion); + } +} + +static expr_t * +cast_math (type_t *dstType, type_t *srcType, expr_t *expr) +{ + pr_type_t src_value[type_size (srcType)]; + pr_type_t dst_value[type_size (dstType)]; + + value_store (src_value, srcType, expr); + + do_conversion (dst_value, dstType, src_value, srcType, expr); + + expr_t *val = new_expr (); + val->type = ex_value; + val->e.value = new_type_value (dstType, dst_value); + return val; +} + +expr_t * +cast_expr (type_t *dstType, expr_t *e) +{ + expr_t *c; + type_t *srcType; + + convert_name (e); + + if (e->type == ex_error) + return e; + + dstType = (type_t *) unalias_type (dstType); //FIXME cast + srcType = get_type (e); + + if (dstType == srcType) + return e; + + if ((dstType == type_default && is_enum (srcType)) + || (is_enum (dstType) && srcType == type_default)) + return e; + if ((is_ptr (dstType) && is_string (srcType)) + || (is_string (dstType) && is_ptr (srcType))) { + c = new_alias_expr (dstType, e); + return c; + } + if (!(is_ptr (dstType) && (is_ptr (srcType) || is_integral (srcType) + || is_array (srcType))) + && !(is_integral (dstType) && is_ptr (srcType)) + && !(is_func (dstType) && is_func (srcType)) + && !(is_math (dstType) && is_math (srcType) + && type_width (dstType) == type_width (srcType)) + && !((is_int (dstType) || is_uint (dstType)) + && (is_short (srcType) || is_ushort (srcType)) + // [u]short is always width 0 + && type_width (dstType) == 1)) { + return cast_error (e, srcType, dstType); + } + if (is_array (srcType)) { + return address_expr (e, dstType->t.fldptr.type); + } + if (is_short (srcType)) { + e = new_int_expr (expr_short (e)); + srcType = &type_int; + } else if (is_ushort (srcType)) { + e = new_int_expr (expr_ushort (e)); + srcType = &type_int; + } + if (is_constant (e) && is_math (dstType) && is_math (srcType)) { + return cast_math (dstType, srcType, e); + } else if (is_integral (dstType) && is_integral (srcType)) { + c = new_alias_expr (dstType, e); + } else if (is_scalar (dstType) && is_scalar (srcType)) { + c = new_unary_expr ('C', e); + c->e.expr.type = dstType; + } else if (e->type == ex_uexpr && e->e.expr.op == '.') { + e->e.expr.type = dstType; + c = e; + } else { + c = new_alias_expr (dstType, e); + } + return c; +} From 04f60e5ff1586eefbcefd498df6ca0923c291b31 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 27 Apr 2022 21:45:05 +0900 Subject: [PATCH 11/34] [qfcc] Rework vector expression handling Use with quaternions and vectors is a little broken in that vec4/quaternion and vec3/vector are not the same types (by design) and thus a cast is needed (not what I want, though). However, creating vectors (that happen to be int due to int constants) does seem to be working nicely otherwise. --- tools/qfcc/include/expr.h | 2 - tools/qfcc/source/dot_expr.c | 36 +---- tools/qfcc/source/expr.c | 5 +- tools/qfcc/source/expr_assign.c | 84 +++--------- tools/qfcc/source/expr_binary.c | 2 - tools/qfcc/source/expr_vector.c | 227 +++++++++++++------------------- tools/qfcc/source/statements.c | 71 +++------- 7 files changed, 138 insertions(+), 289 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 3c2f2a555..455f8b4da 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -761,8 +761,6 @@ expr_t *new_param_expr (struct type_s *type, int num); */ void convert_name (expr_t *e); -expr_t *convert_vector (expr_t *e); - expr_t *append_expr (expr_t *block, expr_t *e); expr_t *prepend_expr (expr_t *block, expr_t *e); diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index 29c5ac319..9a1033df4 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -461,39 +461,9 @@ print_vector (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) { int indent = level * 2 + 2; - if (is_vector(e->e.vector.type)) { - expr_t *x = e->e.vector.list; - expr_t *y = x->next; - expr_t *z = y->next; - _print_expr (dstr, x, level, id, next); - _print_expr (dstr, y, level, id, next); - _print_expr (dstr, z, level, id, next); - dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, x); - dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, y); - dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, z); - } - if (is_quaternion(e->e.vector.type)) { - if (e->e.vector.list->next->next) { - expr_t *x = e->e.vector.list; - expr_t *y = x->next; - expr_t *z = y->next; - expr_t *w = z->next; - _print_expr (dstr, x, level, id, next); - _print_expr (dstr, y, level, id, next); - _print_expr (dstr, z, level, id, next); - _print_expr (dstr, w, level, id, next); - dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, x); - dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, y); - dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, z); - dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, w); - } else { - expr_t *v = e->e.vector.list; - expr_t *s = v->next; - _print_expr (dstr, v, level, id, next); - _print_expr (dstr, s, level, id, next); - dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, v); - dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, s); - } + for (expr_t *ele = e->e.vector.list; ele; ele = ele->next) { + _print_expr (dstr, ele, level, id, next); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, ele); } dasprintf (dstr, "%*se_%p [label=\"vector %d\"];\n", indent, "", e, e->line); diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 388ab8e14..5a057090b 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -2104,15 +2104,14 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params) // expression tree // That, or always use a temp, since it should get optimized out if (has_function_call (e)) { - expr_t *cast = cast_expr (arg_types[i], convert_vector (e)); + expr_t *cast = cast_expr (arg_types[i], e); expr_t *tmp = new_temp_def_expr (arg_types[i]); *a = expr_file_line (tmp, e); arg_exprs[arg_expr_count][0] = expr_file_line (cast, e); arg_exprs[arg_expr_count][1] = *a; arg_expr_count++; } else { - *a = expr_file_line (cast_expr (arg_types[i], convert_vector (e)), - e); + *a = expr_file_line (cast_expr (arg_types[i], e), e); } a = &(*a)->next; } diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index e193de6aa..59c69c23a 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -211,73 +211,31 @@ check_types_compatible (expr_t *dst, expr_t *src) return type_mismatch (dst, src, '='); } +static int +copy_elements (expr_t *block, expr_t *dst, expr_t *src, int base) +{ + int index = 0; + for (expr_t *e = src->e.vector.list; e; e = e->next) { + if (e->type == ex_vector) { + index += copy_elements (block, dst, e, index + base); + } else { + expr_t *dst_ele = array_expr (dst, new_int_expr (index + base)); + append_expr (block, assign_expr (dst_ele, e)); + index += type_width (get_type (e)); + } + } + return index; +} + static expr_t * assign_vector_expr (expr_t *dst, expr_t *src) { - expr_t *dx, *sx; - expr_t *dy, *sy; - expr_t *dz, *sz; - expr_t *dw, *sw; - expr_t *ds, *ss; - expr_t *dv, *sv; - expr_t *block; - - if (src->type == ex_vector) { - src = convert_vector (src); - if (src->type != ex_vector) { - // src was constant and thus converted - return assign_expr (dst, src); - } - } if (src->type == ex_vector && dst->type != ex_vector) { - if (is_vector(src->e.vector.type)) { - // guaranteed to have three elements - sx = src->e.vector.list; - sy = sx->next; - sz = sy->next; - dx = field_expr (dst, new_name_expr ("x")); - dy = field_expr (dst, new_name_expr ("y")); - dz = field_expr (dst, new_name_expr ("z")); - block = new_block_expr (); - append_expr (block, assign_expr (dx, sx)); - append_expr (block, assign_expr (dy, sy)); - append_expr (block, assign_expr (dz, sz)); - block->e.block.result = dst; - return block; - } - if (is_quaternion(src->e.vector.type)) { - // guaranteed to have two or four elements - if (src->e.vector.list->next->next) { - // four vals: x, y, z, w - sx = src->e.vector.list; - sy = sx->next; - sz = sy->next; - sw = sz->next; - dx = field_expr (dst, new_name_expr ("x")); - dy = field_expr (dst, new_name_expr ("y")); - dz = field_expr (dst, new_name_expr ("z")); - dw = field_expr (dst, new_name_expr ("w")); - block = new_block_expr (); - append_expr (block, assign_expr (dx, sx)); - append_expr (block, assign_expr (dy, sy)); - append_expr (block, assign_expr (dz, sz)); - append_expr (block, assign_expr (dw, sw)); - block->e.block.result = dst; - return block; - } else { - // v, s - sv = src->e.vector.list; - ss = sv->next; - dv = field_expr (dst, new_name_expr ("v")); - ds = field_expr (dst, new_name_expr ("s")); - block = new_block_expr (); - append_expr (block, assign_expr (dv, sv)); - append_expr (block, assign_expr (ds, ss)); - block->e.block.result = dst; - return block; - } - } - internal_error (src, "bogus vector expression"); + expr_t *block = new_block_expr (); + + copy_elements (block, dst, src, 0); + block->e.block.result = dst; + return block; } return 0; } diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index b2ac9eece..5ba5b7f18 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -958,7 +958,6 @@ binary_expr (int op, expr_t *e1, expr_t *e2) expr_type_t *expr_type; convert_name (e1); - e1 = convert_vector (e1); // FIXME this is target-specific info and should not be in the // expression tree if (e1->type == ex_alias && is_call (e1->e.alias.expr)) { @@ -982,7 +981,6 @@ binary_expr (int op, expr_t *e1, expr_t *e2) return e1; convert_name (e2); - e2 = convert_vector (e2); if (e2->type == ex_error) return e2; diff --git a/tools/qfcc/source/expr_vector.c b/tools/qfcc/source/expr_vector.c index 8b7cc1495..c9d65ced8 100644 --- a/tools/qfcc/source/expr_vector.c +++ b/tools/qfcc/source/expr_vector.c @@ -62,155 +62,110 @@ #include "tools/qfcc/source/qc-parse.h" expr_t * -convert_vector (expr_t *e) +new_vector_list (expr_t *expr_list) { - float val[4]; + type_t *ele_type = type_default; - if (e->type != ex_vector) - return e; - if (is_vector(e->e.vector.type)) { - // guaranteed to have three elements - expr_t *x = e->e.vector.list; - expr_t *y = x->next; - expr_t *z = y->next; - x = fold_constants (cast_expr (&type_float, x)); - y = fold_constants (cast_expr (&type_float, y)); - z = fold_constants (cast_expr (&type_float, z)); - if (is_constant (x) && is_constant (y) && is_constant (z)) { - val[0] = expr_float(x); - val[1] = expr_float(y); - val[2] = expr_float(z); - return new_vector_expr (val); - } - // at least one of x, y, z is not constant, so rebuild the - // list incase any of them are new expressions - z->next = 0; - y->next = z; - x->next = y; - e->e.vector.list = x; - return e; - } - if (is_quaternion(e->e.vector.type)) { - // guaranteed to have two or four elements - if (e->e.vector.list->next->next) { - // four vals: x, y, z, w - expr_t *x = e->e.vector.list; - expr_t *y = x->next; - expr_t *z = y->next; - expr_t *w = z->next; - x = fold_constants (cast_expr (&type_float, x)); - y = fold_constants (cast_expr (&type_float, y)); - z = fold_constants (cast_expr (&type_float, z)); - w = fold_constants (cast_expr (&type_float, w)); - if (is_constant (x) && is_constant (y) && is_constant (z) - && is_constant (w)) { - val[0] = expr_float(x); - val[1] = expr_float(y); - val[2] = expr_float(z); - val[3] = expr_float(w); - return new_quaternion_expr (val); - } - // at least one of x, y, z, w is not constant, so rebuild the - // list incase any of them are new expressions - w->next = 0; - z->next = w; - y->next = z; - x->next = y; - e->e.vector.list = x; - return e; - } else { - // v, s - expr_t *v = e->e.vector.list; - expr_t *s = v->next; + // lists are built in reverse order + expr_list = reverse_expr_list (expr_list); - v = convert_vector (v); - s = fold_constants (cast_expr (&type_float, s)); - if (is_constant (v) && is_constant (s)) { - memcpy (val, expr_vector (v), 3 * sizeof (float)); - val[3] = expr_float (s); - return new_quaternion_expr (val); - } - // Either v or s is not constant, so can't convert to a quaternion - // constant. - // Rebuild the list in case v or s is a new expression - // the list will always be v, s - s->next = 0; - v->next = s; - e->e.vector.list = v; - return e; - } - } - internal_error (e, "bogus vector expression"); -} - -expr_t * -new_vector_list (expr_t *e) -{ - expr_t *t; - int count; - type_t *type = &type_vector; - expr_t *vec; - - e = reverse_expr_list (e); // put the elements in the right order - for (t = e, count = 0; t; t = t->next) + int width = 0; + int count = 0; + for (expr_t *e = expr_list; e; e = e->next) { count++; + type_t *t = get_type (e); + if (!t) { + return e; + } + if (!is_math (t)) { + return error (e, "invalid type for vector element"); + } + width += type_width (t); + if (is_nonscalar (t)) { + t = base_type (t); + } + if (type_promotes (t, ele_type)) { + ele_type = t; + } + } + if (width < 2) { + return error (expr_list, "not a vector"); + } + if (width > 4) { + return error (expr_list, "resulting vector is too large: %d elements", + width); + } + + int all_constant = 1; + expr_t *elements[count + 1]; + elements[count] = 0; + count = 0; + for (expr_t *e = expr_list; e; e = e->next) { + int cast_width = type_width (get_type (e)); + type_t *cast_type = vector_type (ele_type, cast_width); + elements[count] = cast_expr (cast_type, fold_constants (e)); + all_constant = all_constant && is_constant (elements[count]); + count++; + } + switch (count) { case 4: - type = &type_quaternion; + // all scalars (otherwise width would be too large) + break; case 3: - // quaternion or vector. all expressions must be compatible with - // a float (ie, a scalar) - for (t = e; t; t = t->next) { - if (t->type == ex_error) { - return t; - } - if (!is_scalar (get_type (t))) { - return error (t, "invalid type for vector element"); + // shuffle any vectors to the beginning of the list (there should + // be only one, but futhre...) + for (int i = 1; i < count; i++) { + if (is_nonscalar (get_type (elements[i]))) { + expr_t *t = elements[i]; + int j = i; + for (; j > 0 && is_scalar (get_type (elements[j])); j--) { + elements[j] = elements[j - 1]; + } + elements[j] = t; } } - vec = new_expr (); - vec->type = ex_vector; - vec->e.vector.type = type; - vec->e.vector.list = e; break; case 2: - if (e->type == ex_error || e->next->type == ex_error) { - return e; + if (is_scalar (get_type (elements[0])) + && is_nonscalar (get_type (elements[1]))) { + // swap s, v to be v, s (ie, vector always comes before scalar) + expr_t *t = elements[0]; + elements[0] = elements[1]; + elements[1] = t; } - if (is_scalar (get_type (e)) && is_scalar (get_type (e->next))) { - // scalar, scalar - // expand [x, y] to [x, y, 0] - e->next->next = new_float_expr (0); - vec = new_expr (); - vec->type = ex_vector; - vec->e.vector.type = type; - vec->e.vector.list = e; - break; - } - // quaternion. either scalar, vector or vector, scalar - if (is_scalar (get_type (e)) - && is_vector (get_type (e->next))) { - // scalar, vector - // swap expressions - t = e; - e = e->next; - e->next = t; - t->next = 0; - } else if (is_vector (get_type (e)) - && is_scalar (get_type (e->next))) { - // vector, scalar - // do nothing - } else { - return error (t, "invalid types for vector elements"); - } - // v, s - vec = new_expr (); - vec->type = ex_vector; - vec->e.vector.type = &type_quaternion; - vec->e.vector.list = e; break; - default: - return error (e, "invalid number of elements in vector exprssion"); + case 1: + if (is_scalar (get_type (elements[0]))) { + internal_error (expr_list, "confused about vectors"); + } + // it's already a vector + return elements[0]; } + + if (all_constant) { + type_t *vec_type = vector_type (ele_type, width); + pr_type_t value[type_size (vec_type)]; + + for (int i = 0, offs = 0; i < count; i++) { + type_t *src_type = get_type (elements[i]); + value_store (value + offs, src_type, elements[i]); + offs += type_size (src_type); + } + + expr_t *vec = new_expr (); + vec->type = ex_value; + vec->e.value = new_type_value (vec_type, value); + return vec; + } + + for (int i = 0; i < count; i++) { + elements[i]->next = elements[i + 1]; + } + + expr_t *vec = new_expr (); + vec->type = ex_vector; + vec->e.vector.type = vector_type (ele_type, width); + vec->e.vector.list = elements[0]; return vec; } diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 7c7ad4d4b..140023998 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -1926,13 +1926,28 @@ expr_temp (sblock_t *sblock, expr_t *e, operand_t **op) return sblock; } +static int +statement_copy_elements (sblock_t **sblock, expr_t *dst, expr_t *src, int base) +{ + int index = 0; + for (expr_t *e = src->e.vector.list; e; e = e->next) { + if (e->type == ex_vector) { + index += statement_copy_elements (sblock, dst, e, index + base); + } else { + int size = type_size (base_type (get_type (dst))); + type_t *src_type = get_type (e); + expr_t *dst_ele = new_offset_alias_expr (src_type, dst, + size * (index + base)); + index += type_width (src_type); + *sblock = statement_slist (*sblock, assign_expr (dst_ele, e)); + } + } + return index; +} + static sblock_t * expr_vector_e (sblock_t *sblock, expr_t *e, operand_t **op) { - expr_t *x, *y, *z, *w; - expr_t *s, *v; - expr_t *ax, *ay, *az, *aw; - expr_t *as, *av; expr_t *tmp; type_t *vec_type = get_type (e); int file = pr.source_file; @@ -1942,52 +1957,8 @@ expr_vector_e (sblock_t *sblock, expr_t *e, operand_t **op) pr.source_line = e->line; tmp = new_temp_def_expr (vec_type); - if (is_vector(vec_type)) { - // guaranteed to have three elements - x = e->e.vector.list; - y = x->next; - z = y->next; - ax = new_name_expr ("x"); - ay = new_name_expr ("y"); - az = new_name_expr ("z"); - ax = assign_expr (field_expr (tmp, ax), x); - ay = assign_expr (field_expr (tmp, ay), y); - az = assign_expr (field_expr (tmp, az), z); - sblock = statement_slist (sblock, ax); - sblock = statement_slist (sblock, ay); - sblock = statement_slist (sblock, az); - } else { - // guaranteed to have two or four elements - if (e->e.vector.list->next->next) { - // four vals: x, y, z, w - x = e->e.vector.list; - y = x->next; - z = y->next; - w = z->next; - ax = new_name_expr ("x"); - ay = new_name_expr ("y"); - az = new_name_expr ("z"); - aw = new_name_expr ("w"); - ax = assign_expr (field_expr (tmp, ax), x); - ay = assign_expr (field_expr (tmp, ay), y); - az = assign_expr (field_expr (tmp, az), z); - aw = assign_expr (field_expr (tmp, aw), w); - sblock = statement_slist (sblock, ax); - sblock = statement_slist (sblock, ay); - sblock = statement_slist (sblock, az); - sblock = statement_slist (sblock, aw); - } else { - // v, s - v = e->e.vector.list; - s = v->next; - av = new_name_expr ("v"); - as = new_name_expr ("s"); - av = assign_expr (field_expr (tmp, av), v); - as = assign_expr (field_expr (tmp, as), s); - sblock = statement_slist (sblock, av); - sblock = statement_slist (sblock, as); - } - } + statement_copy_elements (&sblock, tmp, e, 0); + pr.source_file = file; pr.source_line = line; sblock = statement_subexpr (sblock, tmp, op); From 1eb8b61b838bb1c8dc3ade35a90c151e6bbc5d86 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 28 Apr 2022 17:37:56 +0900 Subject: [PATCH 12/34] [qfcc] Clean up handling of value expressions I'd created new_value_expr some time ago, but never used it... Also, replace convert_* with cast_expr to the appropriate type (removes a pile of value check and create code). --- tools/qfcc/include/expr.h | 4 -- tools/qfcc/source/constfold.c | 70 +++------------------ tools/qfcc/source/def.c | 13 ++-- tools/qfcc/source/expr.c | 104 ++++++-------------------------- tools/qfcc/source/expr_binary.c | 8 +-- tools/qfcc/source/expr_cast.c | 5 +- tools/qfcc/source/expr_vector.c | 5 +- 7 files changed, 39 insertions(+), 170 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 455f8b4da..5635141f2 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -768,10 +768,6 @@ expr_t *reverse_expr_list (expr_t *e); void print_expr (expr_t *e); void dump_dot_expr (void *e, const char *filename); -void convert_int (expr_t *e); -void convert_short (expr_t *e); -void convert_short_int (expr_t *e); -void convert_double (expr_t *e); expr_t *convert_nil (expr_t *e, struct type_s *t); expr_t *test_expr (expr_t *e); diff --git a/tools/qfcc/source/constfold.c b/tools/qfcc/source/constfold.c index 6b01bc7f4..6f6287f43 100644 --- a/tools/qfcc/source/constfold.c +++ b/tools/qfcc/source/constfold.c @@ -55,13 +55,6 @@ typedef expr_t *(*operation_t) (int op, expr_t *e, expr_t *e1, expr_t *e2); typedef expr_t *(*unaryop_t) (int op, expr_t *e, expr_t *e1); -static expr_t * -cf_cast_expr (type_t *type, expr_t *e) -{ - e = cast_expr (type, e); - return e; -} - static __attribute__((pure)) int valid_op (int op, int *valid_ops) { @@ -162,33 +155,10 @@ convert_to_float (expr_t *e) if (is_float(get_type (e))) return e; - switch (e->type) { - case ex_value: - switch (e->e.value->lltype) { - case ev_int: - convert_int (e); - return e; - case ev_short: - convert_short (e); - return e; - case ev_double: - convert_double (e); - return e; - default: - internal_error (e, "bad conversion to float: %d", - e->e.value->lltype); - } - break; - case ex_symbol: - case ex_expr: - case ex_uexpr: - case ex_temp: - case ex_block: - e = cf_cast_expr (&type_float, e); - return e; - default: - internal_error (e, 0); - } + expr_t *n = cast_expr (&type_float, e); + n->file = e->file; + n->line = e->line; + return n; } static expr_t * @@ -197,32 +167,10 @@ convert_to_double (expr_t *e) if (is_double(get_type (e))) return e; - switch (e->type) { - case ex_value: - switch (e->e.value->lltype) { - case ev_int: - e->e.value = new_double_val (expr_int (e)); - return e; - case ev_short: - e->e.value = new_double_val (expr_short (e)); - return e; - case ev_float: - e->e.value = new_double_val (expr_float (e)); - return e; - default: - internal_error (e, 0); - } - break; - case ex_symbol: - case ex_expr: - case ex_uexpr: - case ex_temp: - case ex_block: - e = cf_cast_expr (&type_float, e); - return e; - default: - internal_error (e, 0); - } + expr_t *n = cast_expr (&type_double, e); + n->file = e->file; + n->line = e->line; + return n; } static expr_t * @@ -634,7 +582,7 @@ do_op_pointer (int op, expr_t *e, expr_t *e1, expr_t *e2) if (op != '.' && extract_type (e1) != extract_type (e2)) return type_mismatch (e1, e2, op); if (op == '.' && is_uint(get_type (e2))) - e->e.expr.e2 = cf_cast_expr (&type_int, e2); + e->e.expr.e2 = cast_expr (&type_int, e2); return e; } diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index b5d63177a..9d9f04d84 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -380,12 +380,13 @@ init_elements (struct def_s *def, expr_t *eles) reloc_def_op (c->e.labelref.label, &dummy); continue; } else if (c->type == ex_value) { - if (c->e.value->lltype == ev_int && is_float (element->type)) { - convert_int (c); - } - if (is_double (get_type (c)) && is_float (element->type) - && c->implicit) { - convert_double (c); + if (is_float (element->type) + && (is_int (get_type (c)) + || (is_double (get_type (c)) && c->implicit))) { + expr_t *n = cast_expr (&type_float, c); + n->line = c->line; + n->file = c->line; + c = n; } if (get_type (c) != element->type) { error (c, "type mismatch in initializer"); diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 5a057090b..ca71e4403 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -689,109 +689,73 @@ new_name_expr (const char *name) expr_t * new_string_expr (const char *string_val) { - expr_t *e = new_expr (); - e->type = ex_value; - e->e.value = new_string_val (string_val); - return e; + return new_value_expr (new_string_val (string_val)); } expr_t * new_double_expr (double double_val) { - expr_t *e = new_expr (); - e->type = ex_value; - e->e.value = new_double_val (double_val); - return e; + return new_value_expr (new_double_val (double_val)); } expr_t * new_float_expr (float float_val) { - expr_t *e = new_expr (); - e->type = ex_value; - e->e.value = new_float_val (float_val); - return e; + return new_value_expr (new_float_val (float_val)); } expr_t * new_vector_expr (const float *vector_val) { - expr_t *e = new_expr (); - e->type = ex_value; - e->e.value = new_vector_val (vector_val); - return e; + return new_value_expr (new_vector_val (vector_val)); } expr_t * new_entity_expr (int entity_val) { - expr_t *e = new_expr (); - e->type = ex_value; - e->e.value = new_entity_val (entity_val); - return e; + return new_value_expr (new_entity_val (entity_val)); } expr_t * new_field_expr (int field_val, type_t *type, def_t *def) { - expr_t *e = new_expr (); - e->type = ex_value; - e->e.value = new_field_val (field_val, type, def); - return e; + return new_value_expr (new_field_val (field_val, type, def)); } expr_t * new_func_expr (int func_val, type_t *type) { - expr_t *e = new_expr (); - e->type = ex_value; - e->e.value = new_func_val (func_val, type); - return e; + return new_value_expr (new_func_val (func_val, type)); } expr_t * new_pointer_expr (int val, type_t *type, def_t *def) { - expr_t *e = new_expr (); - e->type = ex_value; - e->e.value = new_pointer_val (val, type, def, 0); - return e; + return new_value_expr (new_pointer_val (val, type, def, 0)); } expr_t * new_quaternion_expr (const float *quaternion_val) { - expr_t *e = new_expr (); - e->type = ex_value; - e->e.value = new_quaternion_val (quaternion_val); - return e; + return new_value_expr (new_quaternion_val (quaternion_val)); } expr_t * new_int_expr (int int_val) { - expr_t *e = new_expr (); - e->type = ex_value; - e->e.value = new_int_val (int_val); - return e; + return new_value_expr (new_int_val (int_val)); } expr_t * new_uint_expr (unsigned uint_val) { - expr_t *e = new_expr (); - e->type = ex_value; - e->e.value = new_uint_val (uint_val); - return e; + return new_value_expr (new_uint_val (uint_val)); } expr_t * new_short_expr (short short_val) { - expr_t *e = new_expr (); - e->type = ex_value; - e->e.value = new_short_val (short_val); - return e; + return new_value_expr (new_short_val (short_val)); } int @@ -853,11 +817,9 @@ constant_expr (expr_t *e) } else { return e; } - new = new_expr (); - new->type = ex_value; + new = new_value_expr (value); new->line = e->line; new->file = e->file; - new->e.value = value; return new; } @@ -1508,38 +1470,6 @@ convert_from_bool (expr_t *e, type_t *type) return e; } -void -convert_int (expr_t *e) -{ - float float_val = expr_int (e); - e->type = ex_value; - e->e.value = new_float_val (float_val); -} - -void -convert_short (expr_t *e) -{ - float float_val = expr_short (e); - e->type = ex_value; - e->e.value = new_float_val (float_val); -} - -void -convert_short_int (expr_t *e) -{ - float int_val = expr_short (e); - e->type = ex_value; - e->e.value = new_int_val (int_val); -} - -void -convert_double (expr_t *e) -{ - float float_val = expr_double (e); - e->type = ex_value; - e->e.value = new_float_val (float_val); -} - expr_t * convert_nil (expr_t *e, type_t *t) { @@ -2063,7 +1993,7 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params) convert_from_bool (e, get_type (e)); if (is_int_val (e) && options.code.progsversion == PROG_ID_VERSION) - convert_int (e); + e = cast_expr (&type_float, e); if (options.code.promote_float) { if (is_float (get_type (e))) { t = &type_double; @@ -2280,7 +2210,7 @@ return_expr (function_t *f, expr_t *e) e = convert_from_bool (e, (type_t *) ret_type); //FIXME cast } if (is_float(ret_type) && is_int_val (e)) { - convert_int (e); + e = cast_expr (&type_float, e); t = &type_float; } if (is_void(t)) { @@ -2828,7 +2758,7 @@ build_state_expr (expr_t *e) if (think->type == ex_symbol) think = think_expr (think->e.symbol); if (is_int_val (frame)) - convert_int (frame); + frame = cast_expr (&type_float, frame); if (!type_assignable (&type_float, get_type (frame))) return error (frame, "invalid type for frame number"); if (extract_type (think) != ev_func) @@ -2837,7 +2767,7 @@ build_state_expr (expr_t *e) if (step->next) return error (step->next, "too many state arguments"); if (is_int_val (step)) - convert_int (step); + step = cast_expr (&type_float, step); if (!type_assignable (&type_float, get_type (step))) return error (step, "invalid type for step"); } diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index 5ba5b7f18..be4b5970f 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -787,11 +787,11 @@ double_compare (int op, expr_t *e1, expr_t *e2) if (is_constant (e1) && e1->implicit && is_double (t1) && is_float (t2)) { t1 = &type_float; - convert_double (e1); + e1 = cast_expr (t1, e1); } if (is_float (t1) && is_constant (e2) && e2->implicit && is_double (t2)) { t2 = &type_float; - convert_double (e2); + e2 = cast_expr (t2, e2); } if (is_double (t1)) { if (is_float (t2)) { @@ -1009,11 +1009,11 @@ binary_expr (int op, expr_t *e1, expr_t *e2) if (is_constant (e1) && is_double (t1) && e1->implicit && is_float (t2)) { t1 = &type_float; - convert_double (e1); + e1 = cast_expr (t1, e1); } if (is_constant (e2) && is_double (t2) && e2->implicit && is_float (t1)) { t2 = &type_float; - convert_double (e2); + e2 = cast_expr (t2, e2); } et1 = low_level_type (t1); diff --git a/tools/qfcc/source/expr_cast.c b/tools/qfcc/source/expr_cast.c index 9ec9e9d1a..a02024c0c 100644 --- a/tools/qfcc/source/expr_cast.c +++ b/tools/qfcc/source/expr_cast.c @@ -78,10 +78,7 @@ cast_math (type_t *dstType, type_t *srcType, expr_t *expr) do_conversion (dst_value, dstType, src_value, srcType, expr); - expr_t *val = new_expr (); - val->type = ex_value; - val->e.value = new_type_value (dstType, dst_value); - return val; + return new_value_expr (new_type_value (dstType, dst_value)); } expr_t * diff --git a/tools/qfcc/source/expr_vector.c b/tools/qfcc/source/expr_vector.c index c9d65ced8..f8e891819 100644 --- a/tools/qfcc/source/expr_vector.c +++ b/tools/qfcc/source/expr_vector.c @@ -153,10 +153,7 @@ new_vector_list (expr_t *expr_list) offs += type_size (src_type); } - expr_t *vec = new_expr (); - vec->type = ex_value; - vec->e.value = new_type_value (vec_type, value); - return vec; + return new_value_expr (new_type_value (vec_type, value)); } for (int i = 0; i < count; i++) { From 8ac53664d7b9b5b8aec092b945979cfa3153ea50 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 28 Apr 2022 23:15:22 +0900 Subject: [PATCH 13/34] [simd] Rename VEC_TYPE to QF_VEC_TYPE Makes it less likely to clash with anything (like qfcc's VEC_TYPE :P) --- include/QF/simd/types.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/QF/simd/types.h b/include/QF/simd/types.h index 43d564745..26aceccd0 100644 --- a/include/QF/simd/types.h +++ b/include/QF/simd/types.h @@ -31,7 +31,7 @@ #include #include -#define VEC_TYPE(t,n,s) \ +#define QF_VEC_TYPE(t,n,s) \ typedef t n __attribute__ ((vector_size (s*sizeof (t)))) /** Three element vector type for interfacing with compact data. @@ -41,8 +41,8 @@ */ typedef double vec3d_t[3]; -VEC_TYPE (double, vec2d_t, 2); -VEC_TYPE (int64_t, vec2l_t, 2); +QF_VEC_TYPE (double, vec2d_t, 2); +QF_VEC_TYPE (int64_t, vec2l_t, 2); /** Four element vector type for horizontal (AOS) vector data. * @@ -53,11 +53,11 @@ VEC_TYPE (int64_t, vec2l_t, 2); * a single component from four vectors, or a single row/column (depending on * context) of an Nx4 or 4xN matrix. */ -VEC_TYPE (double, vec4d_t, 4); +QF_VEC_TYPE (double, vec4d_t, 4); /** Used mostly for __builtin_shuffle. */ -VEC_TYPE (int64_t, vec4l_t, 4); +QF_VEC_TYPE (int64_t, vec4l_t, 4); /** Three element vector type for interfacing with compact data. * @@ -66,8 +66,8 @@ VEC_TYPE (int64_t, vec4l_t, 4); */ typedef float vec3f_t[3]; -VEC_TYPE (float, vec2f_t, 2); -VEC_TYPE (int, vec2i_t, 2); +QF_VEC_TYPE (float, vec2f_t, 2); +QF_VEC_TYPE (int, vec2i_t, 2); /** Four element vector type for horizontal (AOS) vector data. * @@ -78,11 +78,11 @@ VEC_TYPE (int, vec2i_t, 2); * a single component from four vectors, or a single row/column (depending on * context) of an Nx4 or 4xN matrix. */ -VEC_TYPE (float, vec4f_t, 4); +QF_VEC_TYPE (float, vec4f_t, 4); /** Used mostly for __builtin_shuffle. */ -VEC_TYPE (int, vec4i_t, 4); +QF_VEC_TYPE (int, vec4i_t, 4); #define VEC2D_FMT "[%.17g, %.17g]" #define VEC2L_FMT "[%"PRIi64", %"PRIi64"]" From 14545c37cfc7c4990e66d000dbcc9e3ca3b80e18 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 29 Apr 2022 11:22:40 +0900 Subject: [PATCH 14/34] [qfcc] Merge printing of values into the one place Having three very similar sets of code for outputting values (just for debug purposes even) got to be a tad annoying. Now there's only one, and in the right place, too (with the other value code). --- tools/qfcc/include/value.h | 1 + tools/qfcc/source/dot_expr.c | 94 ++------------------ tools/qfcc/source/statements.c | 115 +------------------------ tools/qfcc/source/value.c | 151 +++++++++++++++++++++++++++++++++ 4 files changed, 160 insertions(+), 201 deletions(-) diff --git a/tools/qfcc/include/value.h b/tools/qfcc/include/value.h index 5ff0fa925..197c31514 100644 --- a/tools/qfcc/include/value.h +++ b/tools/qfcc/include/value.h @@ -62,6 +62,7 @@ struct ex_value_s *new_type_value (const struct type_s *type, const struct pr_type_s *data); void value_store (pr_type_t *dst, const struct type_s *dstType, const struct expr_s *src); +const char *get_value_string (const struct ex_value_s *value); struct ex_value_s *convert_value (struct ex_value_s *value, struct type_s *type); diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index 9a1033df4..fdf8238e0 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -49,9 +49,10 @@ #include "tools/qfcc/include/expr.h" #include "tools/qfcc/include/method.h" +#include "tools/qfcc/include/strpool.h" #include "tools/qfcc/include/symtab.h" #include "tools/qfcc/include/type.h" -#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/value.h" #include "tools/qfcc/source/qc-parse.h" @@ -491,96 +492,11 @@ static void print_value (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) { int indent = level * 2 + 2; - type_t *type; const char *label = "?!?"; - static dstring_t *type_str; - if (!type_str) { - type_str = dstring_newstr (); - } - - switch (e->e.value->lltype) { - case ev_string: - label = va (0, "\\\"%s\\\"", - quote_string (e->e.value->v.string_val)); - break; - case ev_double: - label = va (0, "f %g", e->e.value->v.double_val); - break; - case ev_float: - label = va (0, "f %g", e->e.value->v.float_val); - break; - case ev_vector: - label = va (0, "'%g %g %g'", - e->e.value->v.vector_val[0], - e->e.value->v.vector_val[1], - e->e.value->v.vector_val[2]); - break; - case ev_quaternion: - label = va (0, "'%g %g %g %g'", - e->e.value->v.quaternion_val[0], - e->e.value->v.quaternion_val[1], - e->e.value->v.quaternion_val[2], - e->e.value->v.quaternion_val[3]); - break; - case ev_ptr: - type = e->e.value->v.pointer.type; - dstring_clearstr(type_str); - if (type) { - print_type_str (type_str, type); - } - if (e->e.value->v.pointer.def) - label = va (0, "(*%s)[%d]<%s>", - type ? type_str->str : "???", - e->e.value->v.pointer.val, - e->e.value->v.pointer.def->name); - else - label = va (0, "(*%s)[%d]", - type ? type_str->str : "???", - e->e.value->v.pointer.val); - break; - case ev_field: - if (e->e.value->v.pointer.def) { - int offset = e->e.value->v.pointer.val; - offset += e->e.value->v.pointer.def->offset; - label = va (0, "field %d", offset); - } else { - label = va (0, "field %d", e->e.value->v.pointer.val); - } - break; - case ev_entity: - label = va (0, "ent %d", e->e.value->v.int_val); - break; - case ev_func: - label = va (0, "func %d", e->e.value->v.int_val); - break; - case ev_int: - label = va (0, "i %d", e->e.value->v.int_val); - break; - case ev_uint: - label = va (0, "u %u", e->e.value->v.uint_val); - break; - case ev_long: - label = va (0, "i %"PRIi64, e->e.value->v.long_val); - break; - case ev_ulong: - label = va (0, "u %"PRIu64, e->e.value->v.ulong_val); - break; - case ev_short: - label = va (0, "s %d", e->e.value->v.short_val); - break; - case ev_ushort: - label = va (0, "us %d", e->e.value->v.ushort_val); - break; - case ev_void: - label = ""; - break; - case ev_invalid: - label = ""; - break; - case ev_type_count: - label = ""; - break; + label = get_value_string (e->e.value); + if (is_string (e->e.value->type)) { + label = quote_string (html_string (label)); } dasprintf (dstr, "%*se_%p [label=\"%s\\n%d\"];\n", indent, "", e, label, e->line); diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 140023998..076ef04d5 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -123,63 +123,7 @@ operand_string (operand_t *op) case op_def: return op->def->name; case op_value: - switch (op->value->lltype) { - case ev_string: - return va (0, "\"%s\"", - quote_string (op->value->v.string_val)); - case ev_double: - return va (0, "%g", op->value->v.double_val); - case ev_float: - return va (0, "%g", op->value->v.float_val); - case ev_vector: - return va (0, "'%g %g %g'", - op->value->v.vector_val[0], - op->value->v.vector_val[1], - op->value->v.vector_val[2]); - case ev_quaternion: - return va (0, "'%g %g %g %g'", - op->value->v.quaternion_val[0], - op->value->v.quaternion_val[1], - op->value->v.quaternion_val[2], - op->value->v.quaternion_val[3]); - case ev_ptr: - if (op->value->v.pointer.def) { - return va (0, "ptr %s+%d", - op->value->v.pointer.def->name, - op->value->v.pointer.val); - } else if(op->value->v.pointer.tempop) { - operand_t *tempop = op->value->v.pointer.tempop; - return va (0, "ptr %s+%d", tempop_string (tempop), - op->value->v.pointer.val); - } else { - return va (0, "ptr %d", op->value->v.pointer.val); - } - case ev_field: - return va (0, "field %d", op->value->v.pointer.val); - case ev_entity: - return va (0, "ent %d", op->value->v.int_val); - case ev_func: - return va (0, "func %d", op->value->v.int_val); - case ev_int: - return va (0, "int %d", op->value->v.int_val); - case ev_uint: - return va (0, "uint %u", op->value->v.uint_val); - case ev_long: - return va (0, "long %"PRIi64, op->value->v.long_val); - case ev_ulong: - return va (0, "ulong %"PRIu64, op->value->v.ulong_val); - case ev_short: - return va (0, "short %d", op->value->v.short_val); - case ev_ushort: - return va (0, "ushort %d", op->value->v.ushort_val); - case ev_void: - return "(void)"; - case ev_invalid: - return "(invalid)"; - case ev_type_count: - return "(type_count)"; - } - break; + return get_value_string (op->value); case op_label: return op->label->name; case op_temp: @@ -209,61 +153,8 @@ _print_operand (operand_t *op) printf ("%s", op->def->name); break; case op_value: - printf ("(%s) ", pr_type_name[op->type->type]); - switch (op->value->lltype) { - case ev_string: - printf ("\"%s\"", op->value->v.string_val); - break; - case ev_double: - printf ("%g", op->value->v.double_val); - break; - case ev_float: - printf ("%g", op->value->v.float_val); - break; - case ev_vector: - printf ("'%g", op->value->v.vector_val[0]); - printf (" %g", op->value->v.vector_val[1]); - printf (" %g'", op->value->v.vector_val[2]); - break; - case ev_quaternion: - printf ("'%g", op->value->v.quaternion_val[0]); - printf (" %g", op->value->v.quaternion_val[1]); - printf (" %g", op->value->v.quaternion_val[2]); - printf (" %g'", op->value->v.quaternion_val[3]); - break; - case ev_ptr: - printf ("(%s)[%d]", - pr_type_name[op->value->v.pointer.type->type], - op->value->v.pointer.val); - break; - case ev_field: - printf ("%d", op->value->v.pointer.val); - break; - case ev_entity: - case ev_func: - case ev_int: - printf ("%d", op->value->v.int_val); - break; - case ev_uint: - printf ("%u", op->value->v.uint_val); - break; - case ev_long: - printf ("%"PRIu64, op->value->v.long_val); - break; - case ev_ulong: - printf ("%"PRIu64, op->value->v.ulong_val); - break; - case ev_short: - printf ("%d", op->value->v.short_val); - break; - case ev_ushort: - printf ("%d", op->value->v.ushort_val); - break; - case ev_void: - case ev_invalid: - case ev_type_count: - internal_error (op->expr, "weird value type"); - } + printf ("(%s) %s", pr_type_name[op->type->type], + get_value_string (op->value)); break; case op_label: printf ("block %p", op->label->dest); diff --git a/tools/qfcc/source/value.c b/tools/qfcc/source/value.c index a88af6ea3..d86b21cbc 100644 --- a/tools/qfcc/source/value.c +++ b/tools/qfcc/source/value.c @@ -45,6 +45,8 @@ #include "QF/mathlib.h" #include "QF/va.h" +#include "QF/simd/types.h" + #include "tools/qfcc/include/qfcc.h" #include "tools/qfcc/include/def.h" #include "tools/qfcc/include/defspace.h" @@ -308,6 +310,155 @@ value_store (pr_type_t *dst, const type_t *dstType, const expr_t *src) memcpy (dst, &val->v, dstSize); } +const char * +get_value_string (const ex_value_t *value) +{ + const type_t *type = value->type; + const char *str = ""; + switch (type->type) { + case ev_string: + return va (0, "\"%s\"", quote_string (value->v.string_val)); + case ev_vector: + case ev_quaternion: + case ev_float: + switch (type_width (type)) { + case 1: + str = va (0, "%.9g", value->v.float_val); + break; + case 2: + str = va (0, VEC2F_FMT, VEC2_EXP (value->v.vec2_val)); + break; + case 3: + str = va (0, "[%.9g, %.9g, %.9g]", + VectorExpand (value->v.vec3_val)); + break; + case 4: + str = va (0, VEC4F_FMT, VEC4_EXP (value->v.vec4_val)); + break; + } + return va (0, "%s %s", type->name, str); + case ev_entity: + case ev_func: + return va (0, "%s %d", type->name, value->v.int_val); + case ev_field: + if (value->v.pointer.def) { + int offset = value->v.pointer.val; + offset += value->v.pointer.def->offset; + return va (0, "field %d", offset); + } else { + return va (0, "field %d", value->v.pointer.val); + } + case ev_ptr: + if (value->v.pointer.def) { + str = va (0, "<%s>", value->v.pointer.def->name); + } + return va (0, "(* %s)[%d]%s", + value->v.pointer.type + ? get_type_string (value->v.pointer.type) : "???", + value->v.pointer.val, str); + case ev_int: + switch (type_width (type)) { + case 1: + str = va (0, "%"PRIi32, value->v.int_val); + break; + case 2: + str = va (0, VEC2I_FMT, VEC2_EXP (value->v.ivec2_val)); + break; + case 3: + str = va (0, "[%"PRIi32", %"PRIi32", %"PRIi32"]", + VectorExpand (value->v.ivec3_val)); + break; + case 4: + str = va (0, VEC4I_FMT, VEC4_EXP (value->v.ivec4_val)); + break; + } + return va (0, "%s %s", type->name, str); + case ev_uint: + switch (type_width (type)) { + case 1: + str = va (0, "%"PRIu32, value->v.uint_val); + break; + case 2: + str = va (0, "[%"PRIu32", %"PRIi32"]", + VEC2_EXP (value->v.uivec2_val)); + break; + case 3: + str = va (0, "[%"PRIu32", %"PRIi32", %"PRIi32"]", + VectorExpand (value->v.uivec3_val)); + break; + case 4: + str = va (0, "[%"PRIu32", %"PRIi32", %"PRIi32", %"PRIi32"]", + VEC4_EXP (value->v.uivec4_val)); + break; + } + return va (0, "%s %s", type->name, str); + case ev_short: + return va (0, "%s %"PRIi16, type->name, value->v.short_val); + case ev_ushort: + return va (0, "%s %"PRIu16, type->name, value->v.ushort_val); + case ev_double: + switch (type_width (type)) { + case 1: + str = va (0, "%.17g", value->v.double_val); + break; + case 2: + str = va (0, VEC2D_FMT, VEC2_EXP (value->v.dvec2_val)); + break; + case 3: + str = va (0, "[%.17g, %.17g, %.17g]", + VectorExpand (value->v.dvec3_val)); + break; + case 4: + str = va (0, VEC4D_FMT, VEC4_EXP (value->v.dvec4_val)); + break; + } + return va (0, "%s %s", type->name, str); + case ev_long: + switch (type_width (type)) { + case 1: + str = va (0, "%"PRIi64, value->v.long_val); + break; + case 2: + str = va (0, VEC2L_FMT, VEC2_EXP (value->v.lvec2_val)); + break; + case 3: + str = va (0, "[%"PRIi64", %"PRIi64", %"PRIi64"]", + VectorExpand (value->v.lvec3_val)); + break; + case 4: + str = va (0, VEC4L_FMT, VEC4_EXP (value->v.lvec4_val)); + break; + } + return va (0, "%s %s", type->name, str); + case ev_ulong: + switch (type_width (type)) { + case 1: + str = va (0, "%"PRIu64, value->v.ulong_val); + break; + case 2: + str = va (0, "[%"PRIu64", %"PRIi64"]", + VEC2_EXP (value->v.ulvec2_val)); + break; + case 3: + str = va (0, "[%"PRIu64", %"PRIi64", %"PRIi64"]", + VectorExpand (value->v.ulvec3_val)); + break; + case 4: + str = va (0, "[%"PRIu64", %"PRIi64", %"PRIi64", %"PRIi64"]", + VEC4_EXP (value->v.ulvec4_val)); + break; + } + return va (0, "%s %s", type->name, str); + case ev_void: + return ""; + case ev_invalid: + return ""; + case ev_type_count: + return ""; + } + return "invalid type"; +} + static hashtab_t *string_imm_defs; static hashtab_t *float_imm_defs; static hashtab_t *vector_imm_defs; From 1da9fff3ae6d70a565d6c0181ed5612b613f6327 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 29 Apr 2022 11:27:27 +0900 Subject: [PATCH 15/34] [qfcc] Simplify immediate value emission This gets immediate values working for the new vector types. --- tools/qfcc/source/value.c | 184 +++++++++----------------------------- 1 file changed, 43 insertions(+), 141 deletions(-) diff --git a/tools/qfcc/source/value.c b/tools/qfcc/source/value.c index d86b21cbc..8661a140b 100644 --- a/tools/qfcc/source/value.c +++ b/tools/qfcc/source/value.c @@ -62,16 +62,11 @@ typedef struct { def_t *def; union { - pr_string_t string_val; - float float_val; - float vector_val[3]; - int entity_val; - int field_val; - int func_val; +#define EV_TYPE(type) pr_##type##_t type##_val; +#include "QF/progs/pr_type_names.h" +#define VEC_TYPE(type_name, base_type) pr_##type_name##_t type_name##_val; +#include "tools/qfcc/include/vec_types.h" ex_pointer_t pointer; - float quaternion_val[4]; - int int_val; - double double_val; } i; } immediate_t; @@ -460,15 +455,8 @@ get_value_string (const ex_value_t *value) } static hashtab_t *string_imm_defs; -static hashtab_t *float_imm_defs; -static hashtab_t *vector_imm_defs; -static hashtab_t *entity_imm_defs; -static hashtab_t *field_imm_defs; -static hashtab_t *func_imm_defs; -static hashtab_t *pointer_imm_defs; -static hashtab_t *quaternion_imm_defs; -static hashtab_t *int_imm_defs; -static hashtab_t *double_imm_defs; +static hashtab_t *fldptr_imm_defs; +static hashtab_t *value_imm_defs; static void imm_free (void *_imm, void *unused) @@ -485,27 +473,13 @@ imm_get_hash (const void *_imm, void *_tab) if (tab == &string_imm_defs) { const char *str = pr.strings->strings + imm->i.string_val; return str ? Hash_String (str) : 0; - } else if (tab == &float_imm_defs) { - return imm->i.int_val; - } else if (tab == &vector_imm_defs) { - return Hash_Buffer (&imm->i.vector_val, sizeof (&imm->i.vector_val)); - } else if (tab == &entity_imm_defs) { - return imm->i.int_val; - } else if (tab == &field_imm_defs) { + } else if (tab == &fldptr_imm_defs) { return Hash_Buffer (&imm->i.pointer, sizeof (&imm->i.pointer)); - } else if (tab == &func_imm_defs) { - return imm->i.int_val; - } else if (tab == &pointer_imm_defs) { - return Hash_Buffer (&imm->i.pointer, sizeof (&imm->i.pointer)); - } else if (tab == &quaternion_imm_defs) { - return Hash_Buffer (&imm->i.quaternion_val, - sizeof (&imm->i.quaternion_val)); - } else if (tab == &double_imm_defs) { - return Hash_Buffer (&imm->i.double_val, sizeof (&imm->i.double_val)); - } else if (tab == &int_imm_defs) { - return imm->i.int_val; + } else if (tab == &value_imm_defs) { + size_t size = type_size (imm->def->type) * sizeof (pr_type_t); + return Hash_Buffer (&imm->i, size) ^ (uintptr_t) imm->def->type; } else { - internal_error (0, 0); + internal_error (0, "invalid immediate hash table"); } } @@ -520,28 +494,14 @@ imm_compare (const void *_imm1, const void *_imm2, void *_tab) const char *str1 = pr.strings->strings + imm1->i.string_val; const char *str2 = pr.strings->strings + imm2->i.string_val; return (str1 == str2 || (str1 && str2 && !strcmp (str1, str2))); - } else if (tab == &float_imm_defs) { - return imm1->i.float_val == imm2->i.float_val; - } else if (tab == &vector_imm_defs) { - return VectorCompare (imm1->i.vector_val, imm2->i.vector_val); - } else if (tab == &entity_imm_defs) { - return imm1->i.entity_val == imm2->i.entity_val; - } else if (tab == &field_imm_defs) { + } else if (tab == &fldptr_imm_defs) { return !memcmp (&imm1->i.pointer, &imm2->i.pointer, sizeof (imm1->i.pointer)); - } else if (tab == &func_imm_defs) { - return imm1->i.func_val == imm2->i.func_val; - } else if (tab == &pointer_imm_defs) { - return !memcmp (&imm1->i.pointer, &imm2->i.pointer, - sizeof (imm1->i.pointer)); - } else if (tab == &quaternion_imm_defs) { - return QuatCompare (imm1->i.quaternion_val, imm2->i.quaternion_val); - } else if (tab == &double_imm_defs) { - return imm1->i.double_val == imm2->i.double_val; - } else if (tab == &int_imm_defs) { - return imm1->i.int_val == imm2->i.int_val; + } else if (tab == &value_imm_defs) { + size_t size = type_size (imm1->def->type) * sizeof (pr_type_t); + return !memcmp (&imm1->i, &imm2->i, size); } else { - internal_error (0, 0); + internal_error (0, "invalid immediate hash table"); } } @@ -676,7 +636,6 @@ emit_value (ex_value_t *value, def_t *def) hashtab_t *tab = 0; type_t *type; ex_value_t val = *value; - immediate_t *imm, search; if (!string_imm_defs) { clear_immediates (); @@ -686,56 +645,36 @@ emit_value (ex_value_t *value, def_t *def) // val.type = type_nil->type; switch (val.lltype) { case ev_entity: - tab = entity_imm_defs; - type = &type_entity; - break; - case ev_field: - tab = field_imm_defs; - type = &type_field; - break; case ev_func: - tab = func_imm_defs; - type = &type_func; - break; - case ev_ptr: - tab = pointer_imm_defs; - type = &type_ptr; - break; case ev_int: case ev_uint: - if (!def || !is_float(def->type)) { - tab = int_imm_defs; - type = &type_int; - break; - } - val.v.float_val = val.v.int_val; - val.lltype = ev_float; case ev_float: - tab = float_imm_defs; - type = &type_float; + case ev_vector: + case ev_quaternion: + case ev_double: + tab = value_imm_defs; + type = val.type; + break; + case ev_field: + case ev_ptr: + tab = fldptr_imm_defs; + type = ev_types[val.lltype]; break; case ev_string: val.v.int_val = ReuseString (val.v.string_val); tab = string_imm_defs; type = &type_string; break; - case ev_vector: - tab = vector_imm_defs; - type = &type_vector; - break; - case ev_quaternion: - tab = quaternion_imm_defs; - type = &type_quaternion; - break; - case ev_double: - tab = double_imm_defs; - type = &type_double; - break; default: - internal_error (0, 0); + internal_error (0, "unexpected value type: %s", + val.type->type < ev_type_count + ? pr_type_name[val.lltype] + : va (0, "%d", val.lltype)); } + def_t search_def = { .type = type }; + immediate_t search = { .def = &search_def }; memcpy (&search.i, &val.v, sizeof (search.i)); - imm = (immediate_t *) Hash_FindElement (tab, &search); + immediate_t *imm = Hash_FindElement (tab, &search); if (imm && strcmp (imm->def->name, ".zero") == 0) { if (def) { imm = 0; //FIXME do full def aliasing @@ -820,15 +759,8 @@ clear_immediates (void) if (value_table) { Hash_FlushTable (value_table); Hash_FlushTable (string_imm_defs); - Hash_FlushTable (float_imm_defs); - Hash_FlushTable (vector_imm_defs); - Hash_FlushTable (entity_imm_defs); - Hash_FlushTable (field_imm_defs); - Hash_FlushTable (func_imm_defs); - Hash_FlushTable (pointer_imm_defs); - Hash_FlushTable (quaternion_imm_defs); - Hash_FlushTable (int_imm_defs); - Hash_FlushTable (double_imm_defs); + Hash_FlushTable (fldptr_imm_defs); + Hash_FlushTable (value_imm_defs); } else { value_table = Hash_NewTable (16381, 0, 0, 0, 0); Hash_SetHashCompare (value_table, value_get_hash, value_compare); @@ -837,49 +769,19 @@ clear_immediates (void) &string_imm_defs, 0); Hash_SetHashCompare (string_imm_defs, imm_get_hash, imm_compare); - float_imm_defs = Hash_NewTable (16381, 0, imm_free, - &float_imm_defs, 0); - Hash_SetHashCompare (float_imm_defs, imm_get_hash, imm_compare); + fldptr_imm_defs = Hash_NewTable (16381, 0, imm_free, + &fldptr_imm_defs, 0); + Hash_SetHashCompare (fldptr_imm_defs, imm_get_hash, imm_compare); - vector_imm_defs = Hash_NewTable (16381, 0, imm_free, - &vector_imm_defs, 0); - Hash_SetHashCompare (vector_imm_defs, imm_get_hash, imm_compare); - - entity_imm_defs = Hash_NewTable (16381, 0, imm_free, - &entity_imm_defs, 0); - Hash_SetHashCompare (entity_imm_defs, imm_get_hash, imm_compare); - - field_imm_defs = Hash_NewTable (16381, 0, imm_free, - &field_imm_defs, 0); - Hash_SetHashCompare (field_imm_defs, imm_get_hash, imm_compare); - - func_imm_defs = Hash_NewTable (16381, 0, imm_free, - &func_imm_defs, 0); - Hash_SetHashCompare (func_imm_defs, imm_get_hash, imm_compare); - - pointer_imm_defs = Hash_NewTable (16381, 0, imm_free, - &pointer_imm_defs, 0); - Hash_SetHashCompare (pointer_imm_defs, imm_get_hash, imm_compare); - - quaternion_imm_defs = Hash_NewTable (16381, 0, imm_free, - &quaternion_imm_defs, 0); - Hash_SetHashCompare (quaternion_imm_defs, imm_get_hash, imm_compare); - - int_imm_defs = Hash_NewTable (16381, 0, imm_free, - &int_imm_defs, 0); - Hash_SetHashCompare (int_imm_defs, imm_get_hash, imm_compare); - - double_imm_defs = Hash_NewTable (16381, 0, imm_free, - &double_imm_defs, 0); - Hash_SetHashCompare (double_imm_defs, imm_get_hash, imm_compare); + value_imm_defs = Hash_NewTable (16381, 0, imm_free, + &value_imm_defs, 0); + Hash_SetHashCompare (value_imm_defs, imm_get_hash, imm_compare); } def = make_symbol (".zero", &type_zero, 0, sc_extern)->s.def; memset (&zero_val, 0, sizeof (zero_val)); make_def_imm (def, string_imm_defs, &zero_val); - make_def_imm (def, float_imm_defs, &zero_val); - make_def_imm (def, entity_imm_defs, &zero_val); - make_def_imm (def, pointer_imm_defs, &zero_val); - make_def_imm (def, int_imm_defs, &zero_val); + make_def_imm (def, fldptr_imm_defs, &zero_val); + make_def_imm (def, value_imm_defs, &zero_val); } From b480590d909132c63f9eba5504975dcf1b4c70f8 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 29 Apr 2022 11:29:14 +0900 Subject: [PATCH 16/34] [qfcc] Treat long, ulong and ushort as math types Not so sure about the value of treating ushort (and short) as a math type, but long and ulong are definitely necessary. --- tools/qfcc/source/type.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index f25cb6eba..b6ca7da62 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -1010,6 +1010,8 @@ is_integral (const type_t *type) type = unalias_type (type); if (is_int (type) || is_uint (type) || is_short (type)) return 1; + if (is_long (type) || is_ulong (type) || is_ushort (type)) + return 1; return is_enum (type); } From d06185336fb26da2594064f44716e6014376bd27 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 29 Apr 2022 11:31:45 +0900 Subject: [PATCH 17/34] [qfcc] Implement component names for the new vector types And simplify vector and quaternion setup as part of the process. Now appropriate x, y, z and w can be used with the new vector types. --- tools/qfcc/source/expr.c | 8 ++++-- tools/qfcc/source/type.c | 60 +++++++++++++++++++++++----------------- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index ca71e4403..66dec9f74 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1330,7 +1330,11 @@ get_struct_field (const type_t *t1, expr_t *e1, expr_t *e2) } field = symtab_lookup (strct, sym->name); if (!field && !is_entity(t1)) { - error (e2, "'%s' has no member named '%s'", t1->name + 4, sym->name); + const char *name = t1->name; + if (!strncmp (name, "tag ", 4)) { + name += 4; + } + error (e2, "'%s' has no member named '%s'", name, sym->name); e1->type = ex_error; } return field; @@ -1391,7 +1395,7 @@ field_expr (expr_t *e1, expr_t *e2) e1 = cast_expr (pointer_type (ivar->type), e1); return unary_expr ('.', e1); } - } else if (is_vector (t1) || is_quaternion (t1) || is_struct (t1)) { + } else if (is_nonscalar (t1) || is_struct (t1)) { symbol_t *field; field = get_struct_field (t1, e1, e2); diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index b6ca7da62..ec52bff4c 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -1301,6 +1301,33 @@ chain_initial_types (void) chain_structural_types (); } +static const char *vector_field_names[] = { "x", "y", "z", "w" }; +//static const char *color_field_names[] = { "r", "g", "b", "a" }; +//static const char *texture_field_names[] = { "s", "t", "p", "q" }; + +static void +build_vector_struct (type_t *type) +{ + ty_meta_e meta = type->meta; + etype_t etype = type->type; + type_t *ele_type = base_type (type); + int width = type_width (type); + + if (!ele_type || width < 2) { + internal_error (0, "%s not a vector type: %p %d", type->name, ele_type, width); + } + + struct_def_t fields[width + 1]; + for (int i = 0; i < width; i++) { + fields[i] = (struct_def_t) { vector_field_names[i], ele_type }; + } + fields[width] = (struct_def_t) {}; + + make_structure (va (0, "@%s", type->name), 's', fields, type); + type->type = etype; + type->meta = meta; +} + void init_types (void) { @@ -1334,17 +1361,6 @@ init_types (void) {"double_val", &type_double}, {0, 0} }; - static struct_def_t vector_struct[] = { - {"x", &type_float}, - {"y", &type_float}, - {"z", &type_float}, - {0, 0} - }; - static struct_def_t quaternion_struct[] = { - {"v", &type_vector}, - {"s", &type_float}, - {0, 0} - }; static struct_def_t type_encoding_struct[] = { {"types", &type_ptr}, {"size", &type_uint}, @@ -1390,9 +1406,7 @@ init_types (void) make_structure ("@zero", 'u', zero_struct, &type_zero); make_structure ("@param", 'u', param_struct, &type_param); - make_structure ("@vector", 's', vector_struct, &type_vector); - type_vector.type = ev_vector; - type_vector.meta = ty_basic; + build_vector_struct (&type_vector); make_structure ("@type_encodings", 's', type_encoding_struct, &type_type_encodings); @@ -1402,24 +1416,20 @@ init_types (void) va_list_struct[1].type = pointer_type (&type_param); make_structure ("@va_list", 's', va_list_struct, &type_va_list); - make_structure ("@quaternion", 's', quaternion_struct, &type_quaternion); - type_quaternion.type = ev_quaternion; - type_quaternion.meta = ty_basic; + build_vector_struct (&type_quaternion); { symbol_t *sym; - sym = new_symbol_type ("x", &type_float); + + sym = new_symbol_type ("v", &type_vector); sym->s.offset = 0; symtab_addsymbol (type_quaternion.t.symtab, sym); - sym = new_symbol_type ("y", &type_float); - sym->s.offset = 1; - symtab_addsymbol (type_quaternion.t.symtab, sym); - sym = new_symbol_type ("z", &type_float); - sym->s.offset = 2; - symtab_addsymbol (type_quaternion.t.symtab, sym); - sym = new_symbol_type ("w", &type_float); + + sym = new_symbol_type ("s", &type_float); sym->s.offset = 3; symtab_addsymbol (type_quaternion.t.symtab, sym); } +#define VEC_TYPE(type_name, base_type) build_vector_struct (&type_##type_name); +#include "tools/qfcc/include/vec_types.h" chain_structural_types (); } From f429777918537edad9f24d219609f79d8a84eb78 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 29 Apr 2022 11:49:45 +0900 Subject: [PATCH 18/34] [qfcc] Extend vector literal processing With this, all vector widths and types are supported: 2, 3, 4 and int, uint, long, ulong, float and double, along with support for suffixes to make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for literals with float-type components, and int (ivec2...) for those with integer-type components. --- tools/qfcc/source/qc-lex.l | 207 ++++++++++++++++++++++++++++++++++--- 1 file changed, 194 insertions(+), 13 deletions(-) diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index c74dcea4a..5a06a64db 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -80,7 +80,9 @@ int yyget_debug (void) __attribute__((pure)); FILE *yyget_in (void) __attribute__((pure)); FILE *yyget_out (void) __attribute__((pure)); -static int keyword_or_id (char *token); +static int keyword_or_id (const char *token); +static expr_t *parse_float_vector (const char *token, int width); +static expr_t *parse_int_vector (const char *token, int width); extern QC_YYSTYPE qc_yylval; @@ -95,7 +97,12 @@ ID [a-zA-Z_][a-zA-Z_0-9]* FLOAT ({D}+|{D}*\.{D}+|{D}+\.{D}*)([eE]{m}?{D}+)? FLOATf {FLOAT}[fF] FLOATd {FLOAT}[dD] +FCOMP {m}?{FLOAT} +FD [fFdD] INT ({D}+|0[xX]{X}+|0[bB]{B}) +ICOMP {m}?{INT} +UL ([uU]?([lL][lL]?)?) +ULFD ({UL}|{FD}) RANGE \.\. ELLIPSIS \.\.\. FRAMEID {ID}(\.{ID})* @@ -122,7 +129,7 @@ STRING \"(\\.|[^"\\])*\" ^{s}*#{s}*pragma{s}+ { BEGIN (PRAGMA); } -{INT}+[uU]?([lL][lL]?)? { +{INT}+{UL}? { const char *c = yytext + yyleng - 1; int i; @@ -187,19 +194,33 @@ STRING \"(\\.|[^"\\])*\" } @ return '@'; -'{s}*{m}?{FLOAT}{s}+{m}?{FLOAT}{s}+{m}?{FLOAT}{s}*' { - vec3_t v; - sscanf (yytext, "' %f %f %f '", - &v[0], &v[1], &v[2]); - qc_yylval.expr = new_vector_expr (v); +'{s}*{ICOMP}{s}+{ICOMP}{s}*'{ULFD}? { + qc_yylval.expr = parse_int_vector (yytext, 2); return VALUE; } -'{s}*{m}?{FLOAT}{s}+{m}?{FLOAT}{s}+{m}?{FLOAT}{s}+{m}?{FLOAT}{s}*' { - quat_t q; - sscanf (yytext, "' %f %f %f %f'", - &q[0], &q[1], &q[2], &q[3]); - qc_yylval.expr = new_quaternion_expr (q); +'{s}*{ICOMP}{s}+{ICOMP}{s}+{ICOMP}{s}*'{ULFD}? { + qc_yylval.expr = parse_int_vector (yytext, 3); + return VALUE; + } + +'{s}*{ICOMP}{s}+{ICOMP}{s}+{ICOMP}{s}+{ICOMP}{s}*'{ULFD}? { + qc_yylval.expr = parse_int_vector (yytext, 4); + return VALUE; + } + +'{s}*{FCOMP}{s}+{FCOMP}{s}*'{FD}? { + qc_yylval.expr = parse_float_vector (yytext, 2); + return VALUE; + } + +'{s}*{FCOMP}{s}+{FCOMP}{s}+{FCOMP}{s}*'{FD}? { + qc_yylval.expr = parse_float_vector (yytext, 3); + return VALUE; + } + +'{s}*{FCOMP}{s}+{FCOMP}{s}+{FCOMP}{s}+{FCOMP}{s}*'{FD}? { + qc_yylval.expr = parse_float_vector (yytext, 4); return VALUE; } @@ -453,7 +474,7 @@ process_keyword (keyword_t *keyword, const char *token) } static int -keyword_or_id (char *token) +keyword_or_id (const char *token) { static hashtab_t *keyword_tab; static hashtab_t *qf_keyword_tab; @@ -525,6 +546,166 @@ keyword_or_id (char *token) return NAME; } +static expr_t * +parse_int_vector (const char *token, int width) +{ + char t1 = 0, t2 = 0; + type_t *type = 0; + + union { + pr_long_t l[4]; + pr_type_t t[PR_SIZEOF (dvec4)]; + } long_data = {}; + pr_type_t *data = __builtin_choose_expr ( + sizeof (pr_long_t) == sizeof (long), long_data.t, (void) 0); + + switch (width) { + case 4: + sscanf (token, "' %li %li %li %li '%c%c", + &long_data.l[0], &long_data.l[1], + &long_data.l[2], &long_data.l[3], &t1, &t2); + break; + case 3: + sscanf (token, "' %li %li %li '%c%c", + &long_data.l[0], &long_data.l[1], + &long_data.l[2], &t1, &t2); + break; + case 2: + sscanf (token, "' %li %li '%c%c", + &long_data.l[0], &long_data.l[1], &t1, &t2); + break; + } + t1 = tolower (t1); + t2 = tolower (t2); + switch (t1) { + case 'u': + if (t2 == 'l') { + type = &type_ulong; + } else { + type = &type_uint; + volatile union { + pr_uint_t u[4]; + pr_type_t t[PR_SIZEOF (ivec4)]; + } uint_data = { + .u = { + long_data.l[0], + long_data.l[1], + long_data.l[2], + long_data.l[3], + } + }; + data = (pr_type_t *) uint_data.t; + } + break; + case 'l': + type = &type_long; + break; + case 'f': + type = &type_float; + volatile union { + pr_float_t f[4]; + pr_type_t t[PR_SIZEOF (vec4)]; + } float_data = { + .f = { + long_data.l[0], + long_data.l[1], + long_data.l[2], + long_data.l[3], + } + }; + data = (pr_type_t *) float_data.t; + break; + case 'd': + type = &type_double; + volatile union { + pr_double_t d[4]; + pr_type_t t[PR_SIZEOF (dvec4)]; + } double_data = { + .d = { + long_data.l[0], + long_data.l[1], + long_data.l[2], + long_data.l[3], + } + }; + data = (pr_type_t *) double_data.t; + break; + case 0: + type = &type_int; + volatile union { + pr_int_t i[4]; + pr_type_t t[PR_SIZEOF (ivec4)]; + } int_data = { + .i = { + long_data.l[0], + long_data.l[1], + long_data.l[2], + long_data.l[3], + } + }; + data = (pr_type_t *) int_data.t; + break; + } + type = vector_type (type, width); + expr_t *expr = new_value_expr (new_type_value (type, data)); + expr->implicit = !t1; + return expr; +} + +static expr_t * +parse_float_vector (const char *token, int width) +{ + char t = 0; + type_t *type = 0; + + union { + pr_double_t d[4]; + pr_type_t t[PR_SIZEOF (dvec4)]; + } double_data = {}; + pr_type_t *data = __builtin_choose_expr ( + sizeof (pr_double_t) == sizeof (double), double_data.t, (void) 0); + + switch (width) { + case 4: + sscanf (token, "' %lf %lf %lf %lf '%c", + &double_data.d[0], &double_data.d[1], + &double_data.d[2], &double_data.d[3], &t); + break; + case 3: + sscanf (token, "' %lf %lf %lf '%c", + &double_data.d[0], &double_data.d[1], + &double_data.d[1], &t); + type = (t == 'f' || t == 'F') ? &type_vec3 : &type_dvec3; + break; + case 2: + sscanf (token, "' %lf %lf '%c", + &double_data.d[0], &double_data.d[1], &t); + type = (t == 'f' || t == 'F') ? &type_vec2 : &type_dvec2; + break; + } + if (t == 'f' || t == 'F') { + volatile union { + pr_float_t f[4]; + pr_type_t t[PR_SIZEOF (vec4)]; + } float_data = { + .f = { + double_data.d[0], + double_data.d[1], + double_data.d[2], + double_data.d[3], + } + }; + data = (pr_type_t *) float_data.t; + type = &type_float; + } else { + type = &type_double; + } + type = vector_type (type, width); + expr_t *expr = new_value_expr (new_type_value (type, data)); + expr->implicit = !t; + return expr; +} + #ifdef YY_FLEX_REALLOC_HACK static __attribute__ ((used)) void *(*const yy_flex_realloc_hack)(void *,yy_size_t) = yy_flex_realloc; #else From bf53edf5e39006450e00c62a867c765f98039565 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 29 Apr 2022 15:20:37 +0900 Subject: [PATCH 19/34] [qfcc] Use correct vector expression size in test Vector expressions no longer auto-widen due to the new vector types (I might add such later, but for now this lets the tests try to build (minus actual fixes in qfcc)). --- tools/qfcc/test/vecexpr.r | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/test/vecexpr.r b/tools/qfcc/test/vecexpr.r index 0365ed589..e4ca4489b 100644 --- a/tools/qfcc/test/vecexpr.r +++ b/tools/qfcc/test/vecexpr.r @@ -39,8 +39,8 @@ main () printf("t3(5) = %v\n", v); ret |= 1; } - v = [x, y] / 2; - if (v != [2, 2.5]) { + v = [x, y, 0] / 2; + if (v != [2, 2.5, 0]) { printf("v = %v\n", v); ret |= 1; } From 9c8e13aa4c6c310572b01f53b653ea1cbd857551 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 29 Apr 2022 15:27:12 +0900 Subject: [PATCH 20/34] [qfcc] Implement automatic casting between same-width vectors This allows all the tests to build and pass. I'll need to add tests to ensure warnings happen when they should and that all vec operations are correct (ouch, that'll be a lot of work), but vectors and quaternions are working again. --- tools/qfcc/source/expr.c | 5 ++- tools/qfcc/source/expr_assign.c | 25 ++++++------ tools/qfcc/source/expr_binary.c | 72 +++++++++++++++++++++++++++++++-- tools/qfcc/source/expr_vector.c | 6 ++- tools/qfcc/source/qc-lex.l | 6 ++- tools/qfcc/source/type.c | 12 +++++- 6 files changed, 102 insertions(+), 24 deletions(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 66dec9f74..fe6a10dd3 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -2231,8 +2231,9 @@ return_expr (function_t *f, expr_t *e) } if (!type_assignable (ret_type, t)) { if (!options.traditional) - return error (e, "type mismatch for return value of %s", - f->sym->name); + return error (e, "type mismatch for return value of %s: %s -> %s", + f->sym->name, get_type_string (t), + get_type_string (ret_type)); if (options.warnings.traditional) warning (e, "type mismatch for return value of %s", f->sym->name); diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index 59c69c23a..1bc88faf7 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -173,21 +173,20 @@ check_types_compatible (expr_t *dst, expr_t *src) } if (type_assignable (dst_type, src_type)) { - if (is_scalar (dst_type) && is_scalar (src_type)) { - if (!src->implicit) { - if (is_double (src_type)) { - warning (dst, "assignment of double to %s (use a cast)\n", - dst_type->name); - } - } - // the types are different but cast-compatible - expr_t *new = cast_expr (dst_type, src); - // the cast was a no-op, so the types are compatible at the - // low level (very true for default type <-> enum) - if (new != src) { - return assign_expr (dst, new); + debug (dst, "casting %s to %s", src_type->name, dst_type->name); + if (!src->implicit && !type_promotes (dst_type, src_type)) { + if (is_double (src_type)) { + warning (dst, "assignment of %s to %s (use a cast)\n", + src_type->name, dst_type->name); } } + // the types are different but cast-compatible + expr_t *new = cast_expr (dst_type, src); + // the cast was a no-op, so the types are compatible at the + // low level (very true for default type <-> enum) + if (new != src) { + return assign_expr (dst, new); + } return 0; } // traditional qcc is a little sloppy diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index be4b5970f..454f01fdf 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -642,6 +642,27 @@ static expr_type_t **binary_expr_types[ev_type_count] = { [ev_double] = double_x }; +// supported operators for scalar-vector expressions +static int scalar_vec_ops[] = { '*', '/', '%', MOD, 0 }; +static expr_t * +convert_scalar (expr_t *scalar, int op, expr_t *vec) +{ + int *s_op = scalar_vec_ops; + while (*s_op && *s_op != op) { + s_op++; + } + if (!*s_op) { + return 0; + } + // expand the scalar to a vector of the same width as vec + for (int i = 1; i < type_width (get_type (vec)); i++) { + expr_t *s = copy_expr (scalar); + s->next = scalar; + scalar = s; + } + return new_vector_list (scalar); +} + static expr_t * pointer_arithmetic (int op, expr_t *e1, expr_t *e2) { @@ -1025,12 +1046,55 @@ binary_expr (int op, expr_t *e1, expr_t *e2) return invalid_binary_expr(op, e1, e2); if ((t1->width > 1 || t2->width > 1)) { - if (t1 != t2) { + // vector/quaternion and scalar won't get here as vector and quaternion + // are distict types with type.width == 1, but vector and vec3 WILL get + // here because of vec3 being float{3} + if (type_width (t1) == 1) { + // scalar op vec + if (!(e = convert_scalar (e1, op, e2))) { + return invalid_binary_expr (op, e1, e2); + } + e1 = e; + t1 = get_type (e1); + } + if (type_width (t2) == 1) { + // vec op scalar + if (!(e = convert_scalar (e2, op, e1))) { + return invalid_binary_expr (op, e1, e2); + } + e2 = e; + t2 = get_type (e2); + } + if (type_width (t1) != type_width (t2)) { + // vec op vec of different widths return invalid_binary_expr (op, e1, e2); } - e = new_binary_expr (op, e1, e2); - e->e.expr.type = t1; - return e; + if (t1 != t2) { + if (is_float (base_type (t1)) && is_double (base_type (t2)) + && e2->implicit) { + e2 = cast_expr (t1, e2); + } else if (is_double (base_type (t1)) && is_float (base_type (t2)) + && e1->implicit) { + e1 = cast_expr (t2, e1); + } else if (type_promotes (base_type (t1), base_type (t2))) { + e2 = cast_expr (t1, e2); + } else if (type_promotes (base_type (t2), base_type (t1))) { + e1 = cast_expr (t2, e1); + } else { + debug (e1, "%d %d\n", e1->implicit, e2->implicit); + return invalid_binary_expr (op, e1, e2); + } + } + t1 = get_type (e1); + t2 = get_type (e2); + et1 = low_level_type (t1); + et2 = low_level_type (t2); + // both widths are the same at this point + if (t1->width > 1) { + e = new_binary_expr (op, e1, e2); + e->e.expr.type = t1; + return e; + } } expr_type = binary_expr_types[et1][et2]; diff --git a/tools/qfcc/source/expr_vector.c b/tools/qfcc/source/expr_vector.c index f8e891819..0efc2b063 100644 --- a/tools/qfcc/source/expr_vector.c +++ b/tools/qfcc/source/expr_vector.c @@ -97,12 +97,14 @@ new_vector_list (expr_t *expr_list) } int all_constant = 1; + int all_implicit = 1; expr_t *elements[count + 1]; elements[count] = 0; count = 0; for (expr_t *e = expr_list; e; e = e->next) { int cast_width = type_width (get_type (e)); type_t *cast_type = vector_type (ele_type, cast_width); + all_implicit = all_implicit && e->implicit; elements[count] = cast_expr (cast_type, fold_constants (e)); all_constant = all_constant && is_constant (elements[count]); count++; @@ -153,7 +155,9 @@ new_vector_list (expr_t *expr_list) offs += type_size (src_type); } - return new_value_expr (new_type_value (vec_type, value)); + expr_t *vec = new_value_expr (new_type_value (vec_type, value)); + vec->implicit = all_implicit; + return vec; } for (int i = 0; i < count; i++) { diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index 5a06a64db..ee63d6791 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -137,10 +137,12 @@ STRING \"(\\.|[^"\\])*\" i = strtol (yytext + 2, 0, 2); else i = strtol (yytext, 0, 0); - if (*c == 'u' || *c == 'U') + if (*c == 'u' || *c == 'U') { qc_yylval.expr = new_int_expr (i);//FIXME - else + } else { qc_yylval.expr = new_int_expr (i); + qc_yylval.expr->implicit = 1; + } return VALUE; } diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index ec52bff4c..567823a4a 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -1124,8 +1124,16 @@ type_assignable (const type_t *dst, const type_t *src) return 1; return 0; } - if (!is_ptr (dst) || !is_ptr (src)) - return is_scalar (dst) && is_scalar (src); + if (!is_ptr (dst) || !is_ptr (src)) { + if (is_scalar (dst) && is_scalar (src)) { + return 1; + } + if (is_nonscalar (dst) && is_nonscalar (src) + && type_width (dst) == type_width (src)) { + return 1; + } + return 0; + } // pointer = pointer // give the object system first shot because the pointee types might have From 9cccb7a4d42138fc44e03426c28629b72a6bdfff Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 29 Apr 2022 15:38:55 +0900 Subject: [PATCH 21/34] [qfcc] Implement ulong, long and uint constants Finally :P --- tools/qfcc/include/expr.h | 3 +++ tools/qfcc/include/value.h | 2 ++ tools/qfcc/source/expr.c | 12 ++++++++++++ tools/qfcc/source/qc-lex.l | 18 +++++++++++++----- tools/qfcc/source/qc-parse.y | 10 ++++++---- tools/qfcc/source/value.c | 16 ++++++++++++++++ 6 files changed, 52 insertions(+), 9 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 5635141f2..0f460445d 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -633,6 +633,9 @@ int expr_int (expr_t *e) __attribute__((pure)); expr_t *new_uint_expr (unsigned uint_val); unsigned expr_uint (expr_t *e) __attribute__((pure)); +expr_t *new_long_expr (pr_long_t long_val); +expr_t *new_ulong_expr (pr_ulong_t ulong_val); + /** Create a new short constant expression node. \param short_val The short constant being represented. diff --git a/tools/qfcc/include/value.h b/tools/qfcc/include/value.h index 197c31514..e8eb5a3a7 100644 --- a/tools/qfcc/include/value.h +++ b/tools/qfcc/include/value.h @@ -56,6 +56,8 @@ struct ex_value_s *new_pointer_val (int val, struct type_s *type, struct ex_value_s *new_quaternion_val (const float *quaternion_val); struct ex_value_s *new_int_val (int int_val); struct ex_value_s *new_uint_val (int uint_val); +struct ex_value_s *new_long_val (pr_long_t long_val); +struct ex_value_s *new_ulong_val (pr_ulong_t ulong_val); struct ex_value_s *new_short_val (short short_val); struct ex_value_s *new_nil_val (struct type_s *type); struct ex_value_s *new_type_value (const struct type_s *type, diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index fe6a10dd3..daea88014 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -752,6 +752,18 @@ new_uint_expr (unsigned uint_val) return new_value_expr (new_uint_val (uint_val)); } +expr_t * +new_long_expr (pr_long_t long_val) +{ + return new_value_expr (new_long_val (long_val)); +} + +expr_t * +new_ulong_expr (pr_ulong_t ulong_val) +{ + return new_value_expr (new_ulong_val (ulong_val)); +} + expr_t * new_short_expr (short short_val) { diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index ee63d6791..495d69aa9 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -131,17 +131,25 @@ STRING \"(\\.|[^"\\])*\" {INT}+{UL}? { const char *c = yytext + yyleng - 1; - int i; + pr_long_t i; if (yytext[0] == '0' && tolower (yytext[1] == 'b')) i = strtol (yytext + 2, 0, 2); else i = strtol (yytext, 0, 0); - if (*c == 'u' || *c == 'U') { - qc_yylval.expr = new_int_expr (i);//FIXME + if (tolower (*c) == 'u') { + if (tolower (c[1]) == 'l') { + qc_yylval.expr = new_ulong_expr (i); + } else { + qc_yylval.expr = new_uint_expr (i); + } } else { - qc_yylval.expr = new_int_expr (i); - qc_yylval.expr->implicit = 1; + if (tolower (c[1]) == 'l') { + qc_yylval.expr = new_long_expr (i); + } else { + qc_yylval.expr = new_int_expr (i); + qc_yylval.expr->implicit = 1; + } } return VALUE; } diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 29029e543..5355a7981 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -94,7 +94,7 @@ int yylex (void); %union { int op; - int size; + unsigned size; specifier_t spec; void *pointer; // for ensuring pointer values are null struct type_s *type; @@ -1131,11 +1131,13 @@ abs_decl array_decl : '[' expr ']' { - if (!is_int_val ($2) || expr_int ($2) < 1) { + if (is_int_val ($2) && expr_int ($2) > 0) { + $$ = expr_int ($2); + } else if (is_uint_val ($2) && expr_uint ($2) > 0) { + $$ = expr_uint ($2); + } else { error (0, "invalid array size"); $$ = 0; - } else { - $$ = expr_int ($2); } } | '[' ']' { $$ = 0; } diff --git a/tools/qfcc/source/value.c b/tools/qfcc/source/value.c index 8661a140b..bd8ac599e 100644 --- a/tools/qfcc/source/value.c +++ b/tools/qfcc/source/value.c @@ -240,6 +240,22 @@ new_uint_val (int uint_val) return find_value (&val); } +ex_value_t * +new_long_val (pr_long_t long_val) +{ + ex_value_t val = { .v = { .long_val = long_val } }; + set_val_type (&val, &type_long); + return find_value (&val); +} + +ex_value_t * +new_ulong_val (pr_ulong_t ulong_val) +{ + ex_value_t val = { .v = { .ulong_val = ulong_val } }; + set_val_type (&val, &type_ulong); + return find_value (&val); +} + ex_value_t * new_short_val (short short_val) { From 547cae03ae4344864e12e786b497261677e01faa Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 29 Apr 2022 19:18:21 +0900 Subject: [PATCH 22/34] [qfcc] Copy parameter types when registering new function type This fixes an error that's been lurking for over two years (since I made parameters unlimited internally). The problem was the array was being allocated on the stack and a simple struct copy was used to store type type, resulting in a dangling pointer onto the stack. I'm surprised it didn't cause more problems. --- tools/qfcc/source/type.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 567823a4a..bd5d93e62 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -495,6 +495,20 @@ find_type (type_t *type) // allocate a new one check = new_type (); *check = *type; + if (is_func (type)) { + check->t.func.param_types = 0; + const type_t *t = unalias_type (type); + int num_params = t->t.func.num_params; + if (num_params < 0) { + num_params = ~num_params; + } + if (num_params) { + check->t.func.param_types = malloc (sizeof (type_t *) * num_params); + for (int i = 0; i < num_params; i++) { + check->t.func.param_types[i] = t->t.func.param_types[i]; + } + } + } check->freeable = 0; chain_type (check); From 719fe5a935972137f91664a170c2182f7b9ef376 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 29 Apr 2022 20:46:33 +0900 Subject: [PATCH 23/34] [qfcc] Support dot product for all (float) vector types While the code would handle int vector types, there aren't any such instructions, and the expression code shouldn't generate them, but all float (32 and 64 bit) vector types do have a dot product instruction, so check width rather than just vector/quaternion. --- tools/qfcc/source/statements.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 076ef04d5..7d15854f6 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -149,7 +149,7 @@ _print_operand (operand_t *op) { switch (op->op_type) { case op_def: - printf ("(%s) ", pr_type_name[op->type->type]); + printf ("(%s) ", get_type_string (op->type)); printf ("%s", op->def->name); break; case op_value: @@ -160,12 +160,12 @@ _print_operand (operand_t *op) printf ("block %p", op->label->dest); break; case op_temp: - printf ("tmp (%s) %p", pr_type_name[op->type->type], op); + printf ("tmp (%s) %p", get_type_string (op->type), op); if (op->tempop.def) printf (" %s", op->tempop.def->name); break; case op_alias: - printf ("alias(%s,", pr_type_name[op->type->type]); + printf ("alias(%s,", get_type_string (op->type)); _print_operand (op->alias); printf (")"); break; @@ -1633,10 +1633,13 @@ expr_expr (sblock_t *sblock, expr_t *e, operand_t **op) opcode = "cmp"; } if (strcmp (opcode, "dot") == 0) { - if (is_vector (get_type (e->e.expr.e1))) { + if (type_width (get_type (e->e.expr.e1)) == 2) { + opcode = "cdot"; + } + if (type_width (get_type (e->e.expr.e1)) == 3) { opcode = "vdot"; } - if (is_quaternion (get_type (e->e.expr.e1))) { + if (type_width (get_type (e->e.expr.e1)) == 4) { opcode = "qdot"; } } From 69ce0e952d2856742b893499367ed162342ac2f4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 29 Apr 2022 20:49:18 +0900 Subject: [PATCH 24/34] [qfcc] Don't auto-promote vector types through ... Currently, only vector/vec3 and quaternion/vec4 can be printed anyway, but I plan on making explicit format strings for the types, so there should be no need to promote any vector types (and really, any hidden promotion is a bit of a pain, but standards...). --- tools/qfcc/source/expr.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index daea88014..a0037c42a 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -223,16 +223,8 @@ type_mismatch (expr_t *e1, expr_t *e2, int op) expr_t * param_mismatch (expr_t *e, int param, const char *fn, type_t *t1, type_t *t2) { - dstring_t *s1 = dstring_newstr (); - dstring_t *s2 = dstring_newstr (); - - print_type_str (s1, t1); - print_type_str (s2, t2); - e = error (e, "type mismatch for parameter %d of %s: expected %s, got %s", - param, fn, s1->str, s2->str); - dstring_delete (s1); - dstring_delete (s2); + param, fn, get_type_string (t1), get_type_string (t2)); return e; } @@ -2011,11 +2003,11 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params) && options.code.progsversion == PROG_ID_VERSION) e = cast_expr (&type_float, e); if (options.code.promote_float) { - if (is_float (get_type (e))) { + if (is_scalar (get_type (e)) && is_float (get_type (e))) { t = &type_double; } } else { - if (is_double (get_type (e))) { + if (is_scalar (get_type (e)) && is_double (get_type (e))) { if (!e->implicit) { warning (e, "passing double into ... function"); } From 8021848b5b6f25f6c10244c1c719632f48a2a45a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 29 Apr 2022 20:52:57 +0900 Subject: [PATCH 25/34] [qfcc] Support promotions for struct initializers This allows the various vector types to be used to initialized structures and arrays. --- tools/qfcc/source/def.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 9d9f04d84..8e009cb85 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -380,10 +380,17 @@ init_elements (struct def_s *def, expr_t *eles) reloc_def_op (c->e.labelref.label, &dummy); continue; } else if (c->type == ex_value) { - if (is_float (element->type) - && (is_int (get_type (c)) - || (is_double (get_type (c)) && c->implicit))) { - expr_t *n = cast_expr (&type_float, c); + type_t *ctype = get_type (c); + if (ctype != element->type + && type_assignable (element->type, ctype)) { + if (!c->implicit + && !type_promotes (element->type, ctype)) { + warning (c, "initialization of %s with %s" + " (use a cast)\n)", + get_type_string (element->type), + get_type_string (ctype)); + } + expr_t *n = cast_expr (element->type, c); n->line = c->line; n->file = c->line; c = n; From 709a0a338dfaad8febf5a38e018567df6b38ccba Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 29 Apr 2022 20:53:59 +0900 Subject: [PATCH 26/34] [qfcc] Return properly from copying a block expression This came up when investigating an internal error from the line above. It turned out the error was correct (problem with converting scalars to vectors), but the break was not. --- tools/qfcc/source/expr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index a0037c42a..db2305e83 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -322,7 +322,7 @@ copy_expr (expr_t *e) } if (e->e.block.result && !n->e.block.result) internal_error (e, "bogus block result?"); - break; + return n; case ex_expr: n = new_expr (); *n = *e; From 4ed9fc6820691603f4c642cc078472bd8406e802 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Apr 2022 17:40:06 +0900 Subject: [PATCH 27/34] [ruamoko] Switch to 64-bit handles for scene objects The scene id is in the lower 32-bits for all objects (upper 32-bits are 0 for actual scene objects) and entity/transform ids are in the upper 32-bits. Saves having to pass around a second parameter in progs code. --- libs/ruamoko/rua_scene.c | 223 ++++++++++++++++++++------------------- 1 file changed, 113 insertions(+), 110 deletions(-) diff --git a/libs/ruamoko/rua_scene.c b/libs/ruamoko/rua_scene.c index 11aee7eb7..d43a4da7b 100644 --- a/libs/ruamoko/rua_scene.c +++ b/libs/ruamoko/rua_scene.c @@ -76,9 +76,13 @@ rua_scene_free (rua_scene_resources_t *res, rua_scene_t *scene) } static rua_scene_t * __attribute__((pure)) -rua__scene_get (rua_scene_resources_t *res, int id, const char *name) +rua__scene_get (rua_scene_resources_t *res, pr_ulong_t id, const char *name) { - rua_scene_t *scene = PR_RESGET (res->scene_map, id); + rua_scene_t *scene = 0; + + if (id <= 0xffffffffu) { + scene = PR_RESGET (res->scene_map, (pr_int_t) id); + } // scene->prev will be null if the handle is unallocated if (!scene || !scene->prev) { @@ -89,29 +93,42 @@ rua__scene_get (rua_scene_resources_t *res, int id, const char *name) #define rua_scene_get(res, id) rua__scene_get(res, id, __FUNCTION__) static entity_t * __attribute__((pure)) -rua__entity_get (progs_t *pr, rua_scene_t *scene, int id, const char *name) +rua__entity_get (rua_scene_resources_t *res, pr_ulong_t id, const char *name) { - entity_t *ent = Scene_GetEntity (scene->scene, id); + pr_ulong_t scene_id = id & 0xffffffff; + entity_t *ent = 0; + + rua_scene_t *scene = rua__scene_get (res, scene_id, name); + if (scene) { + pr_int_t entity_id = id >> 32; + ent = Scene_GetEntity (scene->scene, entity_id); + } if (!ent) { - PR_RunError (pr, "invalid entity passed to %s", name + 3); + PR_RunError (res->pr, "invalid entity passed to %s", name + 3); } return ent; } -#define rua_entity_get(pr, scene, id) rua__entity_get(pr, scene, id, __FUNCTION__) +#define rua_entity_get(res, id) rua__entity_get(res, id, __FUNCTION__) static transform_t * __attribute__((pure)) -rua__transform_get (progs_t *pr, rua_scene_t *scene, int id, const char *name) +rua__transform_get (rua_scene_resources_t *res, pr_ulong_t id, const char *name) { - transform_t *transform = Scene_GetTransform (scene->scene, id); + pr_ulong_t scene_id = id & 0xffffffff; + transform_t *transform = 0; + + rua_scene_t *scene = rua_scene_get (res, scene_id); + if (scene) { + pr_int_t transform_id = id >> 32; + transform = Scene_GetTransform (scene->scene, transform_id); + } if (!transform) { - PR_RunError (pr, "invalid transform passed to %s", name + 3); + PR_RunError (res->pr, "invalid transform passed to %s", name + 3); } return transform; } -#define rua_transform_get(pr, scene, id) \ - rua__transform_get(pr, scene, id, __FUNCTION__) +#define rua_transform_get(res, id) rua__transform_get(res, id, __FUNCTION__) static int __attribute__((pure)) rua_scene_index (rua_scene_resources_t *res, rua_scene_t *scene) @@ -119,6 +136,9 @@ rua_scene_index (rua_scene_resources_t *res, rua_scene_t *scene) return PR_RESINDEX (res->scene_map, scene); } +#define MAKE_ID(id, sc_id) ((((pr_ulong_t) (id)) << 32) \ + | ((sc_id) & 0xffffffff)) + static void bi_Scene_NewScene (progs_t *pr, void *_res) { @@ -135,7 +155,9 @@ bi_Scene_NewScene (progs_t *pr, void *_res) scene->prev = &res->scenes; res->scenes = scene; - R_INT (pr) = rua_scene_index (res, scene); + // scene id in lower 32-bits for all handles + // zero upper 32-bits zero means scene, otherwise transform or entity + R_ULONG (pr) = MAKE_ID (0, rua_scene_index (res, scene)); } static void @@ -149,7 +171,7 @@ static void bi_Scene_DeleteScene (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); + rua_scene_t *scene = rua_scene_get (res, P_ULONG (pr, 0)); rua_delete_scene (res, scene); } @@ -158,17 +180,21 @@ static void bi_Scene_CreateEntity (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); + pr_ulong_t scene_id = P_ULONG (pr, 0); + rua_scene_t *scene = rua_scene_get (res, scene_id); entity_t *ent = Scene_CreateEntity (scene->scene); - R_INT (pr) = ent->id; + R_ULONG (pr) = MAKE_ID (ent->id, scene_id); } static void bi_Scene_DestroyEntity (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - entity_t *ent = rua_entity_get (pr, scene, P_INT (pr, 1)); + pr_ulong_t id = P_ULONG (pr, 0); + entity_t *ent = rua_entity_get (res, id); + pr_ulong_t scene_id = id & 0xffffffff; + // bad scene caught above + rua_scene_t *scene = rua_scene_get (res, scene_id); Scene_DestroyEntity (scene->scene, ent); } @@ -176,18 +202,18 @@ static void bi_Entity_GetTransform (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - entity_t *ent = rua_entity_get (pr, scene, P_INT (pr, 1)); + pr_ulong_t ent_id = P_ULONG (pr, 0); + entity_t *ent = rua_entity_get (res, ent_id); - R_INT (pr) = ent->transform->id; + // ent_id contains scene id + R_ULONG (pr) = MAKE_ID (ent->transform->id, ent_id); } static void bi_Transform_ChildCount (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); R_UINT (pr) = Transform_ChildCount (transform); } @@ -196,8 +222,7 @@ static void bi_Transform_GetChild (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); transform_t *child = Transform_GetChild (transform, P_UINT (pr, 2)); R_UINT (pr) = child ? child->id : 0; @@ -207,9 +232,8 @@ static void bi_Transform_SetParent (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); - transform_t *parent = rua_transform_get (pr, scene, P_INT (pr, 2)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); + transform_t *parent = rua_transform_get (res, P_ULONG (pr, 1)); Transform_SetParent (transform, parent); } @@ -218,19 +242,19 @@ static void bi_Transform_GetParent (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + pr_ulong_t transform_id = P_ULONG (pr, 0); + transform_t *transform = rua_transform_get (res, transform_id); transform_t *parent = Transform_GetParent (transform); - R_INT (pr) = parent ? parent->id : 0; + // transform_id contains scene id + R_ULONG (pr) = parent ? MAKE_ID (parent->id, transform_id) : 0; } static void bi_Transform_SetTag (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); pr_uint_t tag = P_UINT (pr, 2); Transform_SetTag (transform, tag); } @@ -239,8 +263,7 @@ static void bi_Transform_GetTag (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); R_UINT (pr) = Transform_GetTag (transform); } @@ -249,8 +272,7 @@ static void bi_Transform_GetLocalMatrix (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); Transform_GetLocalMatrix (transform, &R_PACKED (pr, pr_vec4_t)); } @@ -258,8 +280,7 @@ static void bi_Transform_GetLocalInverse (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); Transform_GetLocalInverse (transform, &R_PACKED (pr, pr_vec4_t)); } @@ -267,8 +288,7 @@ static void bi_Transform_GetWorldMatrix (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); Transform_GetWorldMatrix (transform, &R_PACKED (pr, pr_vec4_t)); } @@ -276,8 +296,7 @@ static void bi_Transform_GetWorldInverse (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); Transform_GetWorldInverse (transform, &R_PACKED (pr, pr_vec4_t)); } @@ -285,17 +304,15 @@ static void bi_Transform_SetLocalPosition (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); - Transform_SetLocalPosition (transform, P_PACKED (pr, pr_vec4_t, 2)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); + Transform_SetLocalPosition (transform, P_PACKED (pr, pr_vec4_t, 1)); } static void bi_Transform_GetLocalPosition (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); R_PACKED (pr, pr_vec4_t) = Transform_GetLocalPosition (transform); } @@ -303,17 +320,15 @@ static void bi_Transform_SetLocalRotation (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); - Transform_SetLocalRotation (transform, P_PACKED (pr, pr_vec4_t, 2)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); + Transform_SetLocalRotation (transform, P_PACKED (pr, pr_vec4_t, 1)); } static void bi_Transform_GetLocalRotation (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); R_PACKED (pr, pr_vec4_t) = Transform_GetLocalRotation (transform); } @@ -321,17 +336,15 @@ static void bi_Transform_SetLocalScale (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); - Transform_SetLocalScale (transform, P_PACKED (pr, pr_vec4_t, 2)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); + Transform_SetLocalScale (transform, P_PACKED (pr, pr_vec4_t, 1)); } static void bi_Transform_GetLocalScale (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); R_PACKED (pr, pr_vec4_t) = Transform_GetLocalScale (transform); } @@ -339,17 +352,15 @@ static void bi_Transform_SetWorldPosition (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); - Transform_SetWorldPosition (transform, P_PACKED (pr, pr_vec4_t, 2)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); + Transform_SetWorldPosition (transform, P_PACKED (pr, pr_vec4_t, 1)); } static void bi_Transform_GetWorldPosition (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); R_PACKED (pr, pr_vec4_t) = Transform_GetWorldPosition (transform); } @@ -357,17 +368,15 @@ static void bi_Transform_SetWorldRotation (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); - Transform_SetWorldRotation (transform, P_PACKED (pr, pr_vec4_t, 2)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); + Transform_SetWorldRotation (transform, P_PACKED (pr, pr_vec4_t, 1)); } static void bi_Transform_GetWorldRotation (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); R_PACKED (pr, pr_vec4_t) = Transform_GetWorldRotation (transform); } @@ -375,8 +384,7 @@ static void bi_Transform_GetWorldScale (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); R_PACKED (pr, pr_vec4_t) = Transform_GetWorldScale (transform); } @@ -384,18 +392,16 @@ static void bi_Transform_SetLocalTransform (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); - Transform_SetLocalTransform (transform, P_PACKED (pr, pr_vec4_t, 2), - P_PACKED (pr, pr_vec4_t, 3), P_PACKED (pr, pr_vec4_t, 4)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); + Transform_SetLocalTransform (transform, P_PACKED (pr, pr_vec4_t, 1), + P_PACKED (pr, pr_vec4_t, 2), P_PACKED (pr, pr_vec4_t, 3)); } static void bi_Transform_Forward (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); R_PACKED (pr, pr_vec4_t) = Transform_Forward (transform); } @@ -403,8 +409,7 @@ static void bi_Transform_Right (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); R_PACKED (pr, pr_vec4_t) = Transform_Right (transform); } @@ -412,8 +417,7 @@ static void bi_Transform_Up (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; - rua_scene_t *scene = rua_scene_get (res, P_INT (pr, 0)); - transform_t *transform = rua_transform_get (pr, scene, P_INT (pr, 1)); + transform_t *transform = rua_transform_get (res, P_ULONG (pr, 0)); R_PACKED (pr, pr_vec4_t) = Transform_Up (transform); } @@ -421,44 +425,43 @@ bi_Transform_Up (progs_t *pr, void *_res) #define P(a, s) { .size = (s), .alignment = BITOP_LOG2 (a), } #define bi(x,np,params...) {#x, bi_##x, -1, np, {params}} static builtin_t builtins[] = { - bi(Scene_NewScene, 0), - bi(Scene_DeleteScene, 1, p(ptr)), - bi(Scene_CreateEntity, 1, p(ptr)), - bi(Scene_DestroyEntity, 2, p(ptr), p(ptr)), + bi(Scene_NewScene, 0), + bi(Scene_DeleteScene, 1, p(ulong)), + bi(Scene_CreateEntity, 1, p(ulong)), + bi(Scene_DestroyEntity, 1, p(ulong)), - bi(Entity_GetTransform, 2, p(ptr), p(ptr)), + bi(Entity_GetTransform, 1, p(ulong)), - bi(Transform_ChildCount, 2, p(ptr), p(ptr)), - bi(Transform_GetChild, 3, p(ptr), p(ptr), p(int)), - bi(Transform_SetParent, 3, p(ptr), p(ptr), p(ptr)), - bi(Transform_GetParent, 2, p(ptr), p(ptr)), + bi(Transform_ChildCount, 1, p(ulong)), + bi(Transform_GetChild, 2, p(ulong), p(int)), + bi(Transform_SetParent, 2, p(ulong), p(ulong)), + bi(Transform_GetParent, 1, p(ulong)), - bi(Transform_SetTag, 3, p(ptr), p(ptr), p(uint)), - bi(Transform_GetTag, 2, p(ptr), p(ptr)), + bi(Transform_SetTag, 2, p(ulong), p(uint)), + bi(Transform_GetTag, 1, p(ulong)), - bi(Transform_GetLocalMatrix, 2, p(ptr), p(ptr)), - bi(Transform_GetLocalInverse, 2, p(ptr), p(ptr)), - bi(Transform_GetWorldMatrix, 2, p(ptr), p(ptr)), - bi(Transform_GetWorldInverse, 2, p(ptr), p(ptr)), + bi(Transform_GetLocalMatrix, 1, p(ulong)), + bi(Transform_GetLocalInverse, 1, p(ulong)), + bi(Transform_GetWorldMatrix, 1, p(ulong)), + bi(Transform_GetWorldInverse, 1, p(ulong)), - bi(Transform_SetLocalPosition, 3, p(ptr), p(ptr), p(vec4)), - bi(Transform_GetLocalPosition, 2, p(ptr), p(ptr)), - bi(Transform_SetLocalRotation, 3, p(ptr), p(ptr), p(vec4)), - bi(Transform_GetLocalRotation, 2, p(ptr), p(ptr)), - bi(Transform_SetLocalScale, 3, p(ptr), p(ptr), p(vec4)), - bi(Transform_GetLocalScale, 2, p(ptr), p(ptr)), + bi(Transform_SetLocalPosition, 2, p(ulong), p(vec4)), + bi(Transform_GetLocalPosition, 1, p(ulong)), + bi(Transform_SetLocalRotation, 2, p(ulong), p(vec4)), + bi(Transform_GetLocalRotation, 1, p(ulong)), + bi(Transform_SetLocalScale, 2, p(ulong), p(vec4)), + bi(Transform_GetLocalScale, 1, p(ulong)), - bi(Transform_SetWorldPosition, 3, p(ptr), p(ptr), p(vec4)), - bi(Transform_GetWorldPosition, 2, p(ptr), p(ptr)), - bi(Transform_SetWorldRotation, 3, p(ptr), p(ptr), p(vec4)), - bi(Transform_GetWorldRotation, 2, p(ptr), p(ptr)), - bi(Transform_GetWorldScale, 2, p(ptr), p(ptr)), + bi(Transform_SetWorldPosition, 2, p(ulong), p(vec4)), + bi(Transform_GetWorldPosition, 1, p(ulong)), + bi(Transform_SetWorldRotation, 2, p(ulong), p(vec4)), + bi(Transform_GetWorldRotation, 1, p(ulong)), + bi(Transform_GetWorldScale, 1, p(ulong)), - bi(Transform_SetLocalTransform, 5, p(ptr), p(ptr), - p(vec4), p(vec4), p(vec4)), - bi(Transform_Forward, 2, p(ptr), p(ptr)), - bi(Transform_Right, 2, p(ptr), p(ptr)), - bi(Transform_Up, 2, p(ptr), p(ptr)), + bi(Transform_SetLocalTransform, 4, p(ulong), p(vec4), p(vec4), p(vec4)), + bi(Transform_Forward, 1, p(ulong)), + bi(Transform_Right, 1, p(ulong)), + bi(Transform_Up, 1, p(ulong)), {0} }; From b87a768c43a822f68ccd38778130ceb3a4d99fb9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 30 Apr 2022 10:06:01 +0900 Subject: [PATCH 28/34] [gamecode] Sort debug local defs by address This allows the fuzzy bsearch used to find a def by address to work properly (ie, find the actual def instead of giving some other def + offset). Makes for a much more readable instruction stream. --- libs/gamecode/pr_debug.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 01d9f6ebe..09fec6c90 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -31,8 +31,6 @@ # include "config.h" #endif -#define _GNU_SOURCE // for qsort_r - #ifdef HAVE_STRING_H # include #endif @@ -48,6 +46,7 @@ #include "QF/cvar.h" #include "QF/dstring.h" #include "QF/hash.h" +#include "QF/heapsort.h" #include "QF/mathlib.h" #include "QF/progs.h" #include "QF/qendian.h" @@ -478,6 +477,14 @@ process_compunit (prdeb_resources_t *res, pr_def_t *def) } } +static int +def_compare_sort (const void *_da, const void *_db, void *_res) +{ + pr_def_t da = *(const pr_def_t *)_da; + pr_def_t db = *(const pr_def_t *)_db; + return da.ofs - db.ofs; +} + static int func_compare_sort (const void *_fa, const void *_fb, void *_res) { @@ -552,9 +559,12 @@ PR_DebugSetSym (progs_t *pr, pr_debug_header_t *debug) } res->auxfunction_map[res->auxfunctions[i].function] = &res->auxfunctions[i]; + heapsort_r (res->local_defs + res->auxfunctions[i].local_defs, + res->auxfunctions[i].num_locals, sizeof (pr_def_t), + def_compare_sort, res); } - qsort_r (res->sorted_functions, pr->progs->functions.count, - sizeof (pr_func_t), func_compare_sort, res); + heapsort_r (res->sorted_functions, pr->progs->functions.count, + sizeof (pr_func_t), func_compare_sort, res); for (pr_uint_t i = 0; i < debug->num_locals; i++) { if (type_encodings) { From 3c20dd515e74e936d3c11db62dee177e01f4f75e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 30 Apr 2022 21:58:41 +0900 Subject: [PATCH 29/34] Revert "Don't bother creating an alias for a def of the same type." This reverts commit 2904c619c1b883a29c2b7ea29210b44ee8f298f0. In order to support swizzle operations, I need to be able to alias defs to larger types (eg, float to vec4), but alias_def rightly won't allow this. However, as the plan is to do this in the final steps before emitting the instruction, I plan on creating an alias to a float then adjusting the type in the alias, but to do so without extra shenanigans, I need alias_def to allow aliases to the same type. As a fringe benefit, it makes the code agree with the comment in def.h :P --- tools/qfcc/source/def.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 8e009cb85..bab482a9f 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -180,8 +180,6 @@ alias_def (def_t *def, type_t *type, int offset) internal_error (0, "aliasing a def to a larger type"); if (offset < 0 || offset + type_size (type) > type_size (def->type)) internal_error (0, "invalid alias offset"); - if (type == def->type) - return def; for (alias = def->alias_defs; alias; alias = alias->next) { if (alias->type == type && alias->offset == offset) return alias; From ef9960c6f905f65400a75160cfec00620212e08f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 1 May 2022 10:02:26 +0900 Subject: [PATCH 30/34] [qfcc] Implement support for the swizzle operator The destination operand must be a full four component vector, but the source can be smaller and small sources do not need to be aligned: the offset of the source operand and the swizzle indices are adjusted. The adjustments are done during final statement emission in order to avoid confusing the data flow analyser (and that's when def offsets are known). --- tools/qfcc/include/expr.h | 14 ++++++ tools/qfcc/include/expr_names.h | 1 + tools/qfcc/include/type.h | 30 ++++++++++++ tools/qfcc/source/dot_expr.c | 37 +++++++++++++++ tools/qfcc/source/emit.c | 84 +++++++++++++++++++++++++++++++++ tools/qfcc/source/expr.c | 80 +++++++++++++++++++++++++++++++ tools/qfcc/source/expr_assign.c | 1 + tools/qfcc/source/expr_binary.c | 25 ++++++++-- tools/qfcc/source/opcodes.c | 22 ++++++++- tools/qfcc/source/statements.c | 27 +++++++++++ tools/qfcc/source/type.c | 32 +++++++++++++ 11 files changed, 347 insertions(+), 6 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 0f460445d..b9534086e 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -258,6 +258,17 @@ typedef struct { struct type_s *type; ///< result type } ex_horizontal_t; +//NOTE always operates on vec4 or dvec4, so needs a suitable destination and +//care must be taken when working with smaller source operands (check aligmnet +//and adjust swizzle operation as needed) +typedef struct { + struct expr_s *src; ///< source expression + unsigned source[4]; ///< src component indices + unsigned neg; ///< bitmask of dst components to negate + unsigned zero; ///< bitmask of dst components to 0 + struct type_s *type; ///< result type +} ex_swizzle_t; + #define POINTER_VAL(p) (((p).def ? (p).def->offset : 0) + (p).val) typedef struct expr_s { @@ -293,6 +304,7 @@ typedef struct expr_s { ex_with_t with; ///< with expr param struct type_s *nil; ///< type for nil if known ex_horizontal_t hop; ///< horizontal vector operation + ex_swizzle_t swizzle; ///< vector swizzle operation } e; } expr_t; @@ -480,6 +492,8 @@ expr_t *new_unary_expr (int op, expr_t *e1); */ expr_t *new_horizontal_expr (int op, expr_t *vec, struct type_s *type); +expr_t *new_swizzle_expr (expr_t *src, const char *swizzle); + /** Create a new def reference (non-temporary variable) expression node. \return The new def reference expression node (::def_t). diff --git a/tools/qfcc/include/expr_names.h b/tools/qfcc/include/expr_names.h index 05d1f197a..8c6db70b6 100644 --- a/tools/qfcc/include/expr_names.h +++ b/tools/qfcc/include/expr_names.h @@ -63,5 +63,6 @@ EX_EXPR(adjstk) ///< stack adjust expression (::ex_adjstk_t) EX_EXPR(with) ///< with expression (::ex_with_t) EX_EXPR(args) ///< @args marker in parameter list. no data EX_EXPR(horizontal) ///< horizontal vector operation (::ex_horzontal_t) +EX_EXPR(swizzle) ///< vector swizzle operation (::ex_swizzle_t) ///@} diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 69ca4bc4b..6dde9d55b 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -162,6 +162,36 @@ type_t *field_type (type_t *aux); type_t *pointer_type (type_t *aux); type_t *vector_type (const type_t *ele_type, int width) __attribute__((pure)); type_t *base_type (const type_t *vec_type) __attribute__((pure)); + +/** Return an integral type of same size as the provided type. + + Any 32-bit type will produce type_int (or one of ivec2, ivec3 or ivec4). + Any 64-bit type will produce type_long (lor one of lvec2, lvec3, or lvec4). + + Both type_width() and type_size() of the returned type will match the + provided type. + + \param base Type on which the return type will be based. + \return Matching integral type (int, long, or a vector form), or + null if no such match can be made. +*/ +type_t *int_type (const type_t *base) __attribute__((pure)); + +/** Return a floating point type of same size as the provided type. + + Any 32-bit type will produce type_float (or one of vec2, vec3 or vec4). + Any 64-bit type will produce type_double (lor one of dvec2, dvec3, or + dvec4). + + Both type_width() and type_size() of the returned type will match the + provided type. + + \param base Type on which the return type will be based. + \return Matching floating point type (float, double, or a vector + form), or null if no such match can be made. +*/ +type_t *float_type (const type_t *base) __attribute__((pure)); + type_t *array_type (type_t *aux, int size); type_t *based_array_type (type_t *aux, int base, int top); type_t *alias_type (type_t *type, type_t *alias_chain, const char *name); diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index fdf8238e0..664796915 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -555,6 +555,41 @@ print_args (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) e->line); } +static void +print_horizontal (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) +{ + int indent = level * 2 + 2; + + _print_expr (dstr, e->e.hop.vec, level, id, next); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, e->e.hop.vec); + dasprintf (dstr, "%*se_%p [label=\"hop %s\\n%d\"];\n", indent, "", e, + get_op_string (e->e.hop.op), e->line); +} + +static void +print_swizzle (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) +{ + static char swizzle_components[] = "xyzw"; + int indent = level * 2 + 2; + ex_swizzle_t swiz = e->e.swizzle; + const char *swizzle = ""; + + for (int i = 0; i < 4; i++) { + if (swiz.zero & (1 << i)) { + swizzle = va (0, "%s0", swizzle); + } else { + swizzle = va (0, "%s%s%c", swizzle, + swiz.neg & (1 << i) ? "-" : "", + swizzle_components[swiz.source[i]]); + } + } + + _print_expr (dstr, swiz.src, level, id, next); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, swiz.src); + dasprintf (dstr, "%*se_%p [label=\"swizzle %s\\n%d\"];\n", indent, "", e, + swizzle, e->line); +} + static void _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) { @@ -584,6 +619,8 @@ _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) [ex_adjstk] = print_adjstk, [ex_with] = print_with, [ex_args] = print_args, + [ex_horizontal] = print_horizontal, + [ex_swizzle] = print_swizzle, }; int indent = level * 2 + 2; diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index 30b2d1b4b..d5615a794 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -179,6 +179,74 @@ use_tempop (operand_t *op, expr_t *expr) bug (expr, "temp users went negative: %s", operand_string (op)); } +static def_t * +cover_def_32 (def_t *def, int *adj) +{ + int offset = def->offset; + def_t *cover = def; + + if (def->alias) { + offset += def->alias->offset; + } + *adj = offset & 3; + if (offset & 3) { + if (def->alias) { + cover = alias_def (def->alias, def->type, def->offset); + } else { + cover = alias_def (def, def->type, 0); + } + cover->offset -= offset & 3; + } + return cover; +} + +static def_t * +cover_def_64 (def_t *def, int *adj) +{ + int offset = def->offset; + def_t *cover = def; + + if (def->alias) { + offset += def->alias->offset; + } + if (offset & 1) { + internal_error (0, "misaligned 64-bit swizzle source"); + } + *adj = (offset & 6) >> 1; + if (offset & 6) { + if (def->alias) { + cover = alias_def (def->alias, def->type, def->offset); + } else { + cover = alias_def (def, def->type, 0); + } + cover->offset -= offset & 6; + } + return cover; +} + +static def_t * +cover_def (def_t *def, int *adj) +{ + if (type_size (base_type (def->type)) == 1) { + return cover_def_32 (def, adj); + } else { + return cover_def_64 (def, adj); + } +} + +static void +adjust_swizzle (def_t *def, int adj) +{ + pr_ushort_t swiz = def->offset; + for (int i = 0; i < 8; i += 2) { + pr_ushort_t mask = 3 << i; + pr_ushort_t ind = swiz & mask; + swiz &= ~mask; + swiz |= (ind + (adj << i)) & mask; + } + def->offset = swiz; +} + static void emit_statement (statement_t *statement) { @@ -202,12 +270,28 @@ emit_statement (statement_t *statement) op_b = statement->opb; op_c = statement->opc; } + def_a = get_operand_def (statement->expr, op_a); use_tempop (op_a, statement->expr); def_b = get_operand_def (statement->expr, op_b); use_tempop (op_b, statement->expr); def_c = get_operand_def (statement->expr, op_c); use_tempop (op_c, statement->expr); + + if (strcmp (opcode, "swizzle") == 0) { + op_c->type = float_type (op_c->type); + op_a->type = float_type (op_a->type); + if (!op_c->type || !op_a->type) { + internal_error (statement->expr, "invalid types in swizzle"); + } + if (op_a->width < 4) { + int adj; + def_a = cover_def (def_a, &adj); + adjust_swizzle (def_b, adj); + op_a->width = 4; + } + } + inst = opcode_find (opcode, op_a, op_b, op_c); if (!inst) { diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index db2305e83..595eb1e87 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -195,6 +195,8 @@ get_type (expr_t *e) return &type_va_list; case ex_horizontal: return e->e.hop.type; + case ex_swizzle: + return e->e.swizzle.type; case ex_count: internal_error (e, "invalid expression"); } @@ -425,6 +427,11 @@ copy_expr (expr_t *e) *n = *e; e->e.hop.vec = copy_expr (e->e.hop.vec); return n; + case ex_swizzle: + n = new_expr (); + *n = *e; + e->e.swizzle.src = copy_expr (e->e.swizzle.src); + return n; case ex_count: break; } @@ -611,6 +618,74 @@ new_horizontal_expr (int op, expr_t *vec, type_t *type) return e; } +expr_t * +new_swizzle_expr (expr_t *src, const char *swizzle) +{ + type_t *src_type = get_type (src); + if (!src_type) { + return src; + } + int src_width = type_width (src_type); + // swizzle always generates a *vec4 + ex_swizzle_t swiz = {}; + +#define m(x) (1 << ((x) - 'a')) +#define v(x, mask) (((x) & 0x60) == 0x60 && (m(x) & (mask))) +#define vind(x) ((x) & 3) +#define cind(x) (-(((x) >> 3) ^ (x)) & 3) +#define tind(x) ((((~(x+1)>>2)&1) + x + 1) & 3) + const int color = m('r') | m('g') | m('b') | m('a'); + const int vector = m('x') | m('y') | m('z') | m('w'); + const int texture = m('s') | m('t') | m('p') | m('q'); + + int type_mask = 0; + int comp_count = 0; + + for (const char *s = swizzle; *s; s++) { + if (comp_count >= 4) { + return error (src, "too many components in swizzle"); + } + if (*s == '0') { + swiz.zero |= 1 << comp_count; + comp_count++; + } else if (*s == '-') { + swiz.neg |= 1 << comp_count; + } else { + int ind = 0; + int mask = 0; + if (v (*s, vector)) { + ind = vind (*s); + mask = 1; + } else if (v (*s, color)) { + ind = cind (*s); + mask = 2; + } else if (v (*s, texture)) { + ind = tind (*s); + mask = 4; + } + if (!mask) { + return error (src, "invalid component in swizzle"); + } + if (type_mask & ~mask) { + return error (src, "mixed components in swizzle"); + } + if (ind >= src_width) { + return error (src, "swizzle component out of bounds"); + } + type_mask |= mask; + swiz.source[comp_count++] = ind; + } + } + swiz.zero |= (0xf << comp_count) & 0xf; + swiz.src = new_alias_expr (vector_type (&type_float, src_width), src); + swiz.type = vector_type (base_type (src_type), 4); + + expr_t *expr = new_expr (); + expr->type = ex_swizzle; + expr->e.swizzle = swiz; + return expr; +} + expr_t * new_def_expr (def_t *def) { @@ -1547,6 +1622,8 @@ has_function_call (expr_t *e) return has_function_call (e->e.retrn.ret_val); case ex_horizontal: return has_function_call (e->e.hop.vec); + case ex_swizzle: + return has_function_call (e->e.swizzle.src); case ex_error: case ex_state: case ex_label: @@ -1692,6 +1769,7 @@ unary_expr (int op, expr_t *e) case ex_alias: case ex_assign: case ex_horizontal: + case ex_swizzle: { expr_t *n = new_unary_expr (op, e); @@ -1785,6 +1863,7 @@ unary_expr (int op, expr_t *e) case ex_address: case ex_assign: case ex_horizontal: + case ex_swizzle: if (options.code.progsversion == PROG_VERSION) { return binary_expr (EQ, e, new_nil_expr ()); } else { @@ -1874,6 +1953,7 @@ unary_expr (int op, expr_t *e) case ex_alias: case ex_assign: case ex_horizontal: + case ex_swizzle: bitnot_expr: if (options.code.progsversion == PROG_ID_VERSION) { expr_t *n1 = new_int_expr (-1); diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index 1bc88faf7..b04a98b36 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -142,6 +142,7 @@ is_lvalue (const expr_t *expr) case ex_with: case ex_args: case ex_horizontal: + case ex_swizzle: break; case ex_count: internal_error (expr, "invalid expression"); diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index 454f01fdf..d2e8e59c5 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -654,13 +654,28 @@ convert_scalar (expr_t *scalar, int op, expr_t *vec) if (!*s_op) { return 0; } + // expand the scalar to a vector of the same width as vec - for (int i = 1; i < type_width (get_type (vec)); i++) { - expr_t *s = copy_expr (scalar); - s->next = scalar; - scalar = s; + type_t *vec_type = get_type (vec); + + if (scalar->type == ex_symbol || scalar->type == ex_def + || is_constant (scalar)) { + for (int i = 1; i < type_width (get_type (vec)); i++) { + expr_t *s = copy_expr (scalar); + s->next = scalar; + scalar = s; + } + return new_vector_list (scalar); } - return new_vector_list (scalar); + + char swizzle[] = "xxxx"; + type_t *vec_base = base_type (vec_type); + expr_t *tmp = new_temp_def_expr (vector_type (vec_base, 4)); + expr_t *block = new_block_expr (); + swizzle[type_width (vec_type)] = 0; + append_expr (block, assign_expr (tmp, new_swizzle_expr (scalar, swizzle))); + block->e.block.result = new_alias_expr (vec_type, tmp); + return block; } static expr_t * diff --git a/tools/qfcc/source/opcodes.c b/tools/qfcc/source/opcodes.c index 5c97f780c..d4413e744 100644 --- a/tools/qfcc/source/opcodes.c +++ b/tools/qfcc/source/opcodes.c @@ -41,6 +41,7 @@ #include +#include "tools/qfcc/include/diagnostic.h" #include "tools/qfcc/include/opcodes.h" #include "tools/qfcc/include/options.h" #include "tools/qfcc/include/qfcc.h" @@ -302,7 +303,26 @@ operand_width (const char *opname, operand_t *op) } return op->width; } - +#if 0 + if (!strcmp (name, "swizzle")) { + adjust_swizzle_op (&search_op, 0); + adjust_swizzle_op (&search_op, 2); + } +static void +adjust_swizzle_op (opcode_t *op, int opind) +{ + // swizzle instructions require both operands to be 4 components (4 or 8 + // words) in size with the same alignment. + op->widths[opind] = 4; + if (pr_type_size[op->types[opind]] == 1) { + op->types[opind] = ev_float; + } else if (pr_type_size[op->types[opind]] == 2) { + op->types[opind] = ev_double; + } else { + internal_error (0, "unexpected swizzle op size"); + } +} +#endif static opcode_t * rua_opcode_find (const char *name, operand_t *op_a, operand_t *op_b, operand_t *op_c) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 7d15854f6..4e5010427 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -1783,6 +1783,32 @@ expr_horizontal (sblock_t *sblock, expr_t *e, operand_t **op) return sblock; } +static sblock_t * +expr_swizzle (sblock_t *sblock, expr_t *e, operand_t **op) +{ + const char *opcode = "swizzle"; + statement_t *s; + int swiz = 0; + type_t *res_type = e->e.swizzle.type; + + for (int i = 0; i < 4; i++) { + swiz |= e->e.swizzle.source[i] & 3; + } + swiz |= (e->e.swizzle.neg & 0xf) << 8; + swiz |= (e->e.swizzle.zero & 0xf) << 12; + + s = new_statement (st_expr, opcode, e); + sblock = statement_subexpr (sblock, e->e.swizzle.src, &s->opa); + s->opb = short_operand (swiz, e); + if (!*op) { + *op = temp_operand (res_type, e); + } + s->opc = *op; + sblock_add_statement (sblock, s); + + return sblock; +} + static sblock_t * expr_def (sblock_t *sblock, expr_t *e, operand_t **op) { @@ -1915,6 +1941,7 @@ statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op) [ex_expr] = expr_expr, [ex_uexpr] = expr_uexpr, [ex_horizontal] = expr_horizontal, + [ex_swizzle] = expr_swizzle, [ex_def] = expr_def, [ex_symbol] = expr_symbol, [ex_temp] = expr_temp, diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index bd5d93e62..8b0901339 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -586,6 +586,38 @@ base_type (const type_t *vec_type) return ev_types[vec_type->type]; } +type_t * +int_type (const type_t *base) +{ + int width = type_width (base); + base = base_type (base); + if (!base) { + return 0; + } + if (type_size (base) == 1) { + base = &type_int; + } else if (type_size (base) == 2) { + base = &type_long; + } + return vector_type (base, width); +} + +type_t * +float_type (const type_t *base) +{ + int width = type_width (base); + base = base_type (base); + if (!base) { + return 0; + } + if (type_size (base) == 1) { + base = &type_float; + } else if (type_size (base) == 2) { + base = &type_double; + } + return vector_type (base, width); +} + type_t * array_type (type_t *aux, int size) { From cdd8739577b776af9c9f4911ac22a71f9d763cfc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 1 May 2022 14:05:43 +0900 Subject: [PATCH 31/34] [qfcc] Improve debug printing of statements and operands Makes it easier to check operand base indices and temporary variable addresses when known. --- tools/qfcc/source/opcodes.c | 7 +++++-- tools/qfcc/source/statements.c | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/source/opcodes.c b/tools/qfcc/source/opcodes.c index d4413e744..23da7490b 100644 --- a/tools/qfcc/source/opcodes.c +++ b/tools/qfcc/source/opcodes.c @@ -527,6 +527,9 @@ opcode_print_statement (pr_uint_t addr, dstatement_t *st) } else { mnemonic = pr_opcodes[st_op].mnemonic; } - printf ("%04x (%03x)%-8s %04x %04x %04x\n", - addr, st_op & 0x1ff, mnemonic, st->a, st->b, st->c); + printf ("%04x (%03x)%-8s %d:%04x %d:%04x %d:%04x\n", + addr, st_op & 0x1ff, mnemonic, + (st->op & OP_A_BASE) >> OP_A_SHIFT, st->a, + (st->op & OP_B_BASE) >> OP_B_SHIFT, st->b, + (st->op & OP_C_BASE) >> OP_C_SHIFT, st->c); } diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 4e5010427..28114dedf 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -162,7 +162,8 @@ _print_operand (operand_t *op) case op_temp: printf ("tmp (%s) %p", get_type_string (op->type), op); if (op->tempop.def) - printf (" %s", op->tempop.def->name); + printf (" %s:%04x", op->tempop.def->name, + op->tempop.def->offset); break; case op_alias: printf ("alias(%s,", get_type_string (op->type)); From 7518ba0a2756b8b6f5f8e230cbce8966a58d180d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 1 May 2022 14:07:32 +0900 Subject: [PATCH 32/34] [qfcc] Add failing test case for defspace_alloc_aligned_loc qfcc is putting two temps in the same location due to defspace_alloc_aligned_loc returning the same address when there was a hole caused by an earlier aligned alloc: specifically, a size-3 hole and a size-2 allocation with alignment-2. --- tools/qfcc/test/test-defspace.c | 34 +++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tools/qfcc/test/test-defspace.c b/tools/qfcc/test/test-defspace.c index 17d9ed12e..cbb80d623 100644 --- a/tools/qfcc/test/test-defspace.c +++ b/tools/qfcc/test/test-defspace.c @@ -104,6 +104,39 @@ test_init (void) return pass; } +static int +test_aligned_alloc (void) +{ + defspace_t *space = defspace_new (ds_virtual); + struct { + int size, align; + } allocations[6] = { + { 2, 2 }, + { 2, 2 }, + { 1, 1 }, + { 4, 4 }, + { 2, 2 }, + { 2, 2 }, + }; + int offsets[6]; + for (int i = 0; i < 6; i++) { + offsets[i] = defspace_alloc_aligned_loc (space, allocations[i].size, + allocations[i].align); + } + for (int i = 0; i < 5; i++) { + for (int j = i + 1; j < 6; j++) { + if (offsets[i] == offsets[j]) { + printf ("duplicate offset in allocations"); + printf ("%d %d %d %d %d %d\n", + offsets[0], offsets[1], offsets[2], + offsets[3], offsets[4], offsets[5]); + return 0; + } + } + } + return 1; +} + int main (int argc, const char **argv) { @@ -112,6 +145,7 @@ main (int argc, const char **argv) int pass = 1; pass &= test_init (); + pass &= test_aligned_alloc (); return !pass; } From be4021f8f4cf8e8ef415afd80402d99fd0bfd6de Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 1 May 2022 14:11:11 +0900 Subject: [PATCH 33/34] [qfcc] Actually shrink the unaligned hole This fixes the duplicate allocation caused by an exact fit aligned alloc in an unaligned hole where the padding remains free. --- tools/qfcc/source/defspace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/source/defspace.c b/tools/qfcc/source/defspace.c index a704b45a3..e1dc3b72a 100644 --- a/tools/qfcc/source/defspace.c +++ b/tools/qfcc/source/defspace.c @@ -173,7 +173,8 @@ defspace_alloc_aligned_loc (defspace_t *space, int size, int alignment) // exact fit, so just shrink the block or remove it if there is no // padding (any padding remains free) if (size + pad == loc->size) { - if (!pad) { + loc->size -= size; + if (!loc->size) { *l = loc->next; del_locref (loc); } From b9bd45ad992403a7a4622b30898fc461a17a3b2b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 1 May 2022 14:12:43 +0900 Subject: [PATCH 34/34] [qfcc] Create vector lists only for constants Defs and symbols benefit from swizzling as that's one instruction vs 2-3 for loading a scalar into a vector component by component. Constants are ok because the result gets converted to a vector constant. --- tools/qfcc/source/expr_binary.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index d2e8e59c5..1c0429d09 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -658,8 +658,7 @@ convert_scalar (expr_t *scalar, int op, expr_t *vec) // expand the scalar to a vector of the same width as vec type_t *vec_type = get_type (vec); - if (scalar->type == ex_symbol || scalar->type == ex_def - || is_constant (scalar)) { + if (is_constant (scalar)) { for (int i = 1; i < type_width (get_type (vec)); i++) { expr_t *s = copy_expr (scalar); s->next = scalar;