From df7c08a01033f49c5d0bfb2e1d05a1854f4552e9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 14 Feb 2020 16:38:37 +0900 Subject: [PATCH] Add support for doubles to Ruamoko Only as scalars, I still need to think about what to do for vectors and quaternions due to param size issues. Also, doubles are not yet guaranteed to be correctly aligned. --- include/QF/pr_comp.h | 38 +++++- include/QF/progs.h | 48 +++++++ libs/gamecode/pr_exec.c | 158 +++++++++++++++++++++-- libs/gamecode/pr_opcode.c | 126 +++++++++++++++++++ libs/gamecode/pr_strings.c | 31 +++-- libs/ruamoko/rua_math.c | 223 +++++++++++++++++++++++++++------ nq/include/sv_progs.h | 5 + nq/source/sv_progs.c | 3 + qw/include/sv_progs.h | 5 + qw/source/sv_progs.c | 3 + ruamoko/include/math.h | 73 +++++++---- ruamoko/lib/math.r | 24 ++++ tools/qfcc/include/expr.h | 10 ++ tools/qfcc/include/type.h | 2 + tools/qfcc/include/value.h | 1 + tools/qfcc/source/constfold.c | 222 +++++++++++++++++++++++++++++++- tools/qfcc/source/dot_expr.c | 3 + tools/qfcc/source/expr.c | 34 +++++ tools/qfcc/source/qc-lex.l | 1 + tools/qfcc/source/statements.c | 5 + tools/qfcc/source/type.c | 19 ++- tools/qfcc/source/value.c | 10 ++ 22 files changed, 958 insertions(+), 86 deletions(-) diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index c657a7ca1..122de60b9 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -44,6 +44,7 @@ typedef enum { ev_integer, ev_uinteger, ev_short, // value is embedded in the opcode + ev_double, ev_invalid, // invalid type. used for instruction checking ev_type_count // not a type, gives number of types @@ -305,6 +306,7 @@ typedef enum { OP_PUSH_P, OP_PUSH_Q, OP_PUSH_I, + OP_PUSH_D, OP_PUSHB_S, OP_PUSHB_F, @@ -315,6 +317,7 @@ typedef enum { OP_PUSHB_P, OP_PUSHB_Q, OP_PUSHB_I, + OP_PUSHB_D, OP_PUSHBI_S, OP_PUSHBI_F, @@ -325,6 +328,7 @@ typedef enum { OP_PUSHBI_P, OP_PUSHBI_Q, OP_PUSHBI_I, + OP_PUSHBI_D, OP_POP_S, OP_POP_F, @@ -335,6 +339,7 @@ typedef enum { OP_POP_P, OP_POP_Q, OP_POP_I, + OP_POP_D, OP_POPB_S, OP_POPB_F, @@ -345,6 +350,7 @@ typedef enum { OP_POPB_P, OP_POPB_Q, OP_POPB_I, + OP_POPB_D, OP_POPBI_S, OP_POPBI_F, @@ -355,6 +361,36 @@ typedef enum { OP_POPBI_P, OP_POPBI_Q, OP_POPBI_I, + OP_POPBI_D, + + OP_ADD_D, + OP_SUB_D, + OP_MUL_D, + OP_MUL_QD, + OP_MUL_DQ, + OP_MUL_VD, + OP_MUL_DV, + OP_DIV_D, + OP_MOD_D, + OP_GE_D, + OP_LE_D, + OP_GT_D, + OP_LT_D, + OP_NOT_D, + OP_EQ_D, + OP_NE_D, + OP_CONV_FD, + OP_CONV_DF, + OP_CONV_ID, + OP_CONV_DI, + OP_STORE_D, + OP_STOREB_D, + OP_STOREBI_D, + OP_STOREP_D, + OP_LOAD_D, + OP_LOADB_D, + OP_LOADBI_D, + OP_ADDRESS_D, } pr_opcode_e; typedef struct opcode_s { @@ -423,7 +459,7 @@ typedef struct pr_va_list_s { |(((0x##b) & 0xfff) << 12) \ |(((0x##c) & 0xfff) << 0) ) #define PROG_ID_VERSION 6 -#define PROG_VERSION PROG_VERSION_ENCODE(0,fff,009) +#define PROG_VERSION PROG_VERSION_ENCODE(0,fff,00a) typedef struct dprograms_s { pr_uint_t version; diff --git a/include/QF/progs.h b/include/QF/progs.h index 7631f1de1..f3358c708 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -320,6 +320,18 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define G_FLOAT(p,o) G_var (p, o, float) +/** Access a double global. Can be assigned to. + + \par QC type: + \c double + \param p pointer to ::progs_t VM struct + \param o offset into global data space + \return double lvalue + + \hideinitializer +*/ +#define G_DOUBLE(p,o) (*(double *) ((p)->pr_globals + o)) + /** Access an integer global. Can be assigned to. \par QC type: @@ -510,6 +522,18 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define P_FLOAT(p,n) P_var (p, n, float) +/** Access a double parameter. Can be assigned to. + + \par QC type: + \c double + \param p pointer to ::progs_t VM struct + \param n parameter number (0-7) + \return double lvalue + + \hideinitializer +*/ +#define P_DOUBLE(p,n) (*(double *) ((p)->pr_params[n])) + /** Access an integer parameter. Can be assigned to. \par QC type: @@ -702,6 +726,17 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define R_FLOAT(p) R_var (p, float) +/** Access the VM function return value as a \c double + + \par QC type: + \c double + \param p pointer to ::progs_t VM struct + \return double lvalue + + \hideinitializer +*/ +#define R_DOUBLE(p) (*(double *) ((p)->pr_return)) + /** Access the VM function return value as a \c ::pr_int_t (AKA int32_t) \par QC type: @@ -868,6 +903,18 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define E_FLOAT(e,o) E_var (e, o, float) +/** Access a double entity field. Can be assigned to. + + \par QC type: + \c double + \param e pointer to the entity + \param o field offset into entity data space + \return double lvalue + + \hideinitializer +*/ +#define E_DOUBLE(e,o) (*(double *) ((e)->v + o)) + /** Access an integer entity field. Can be assigned to. \par QC type: @@ -1560,6 +1607,7 @@ struct progs_s { struct hashtab_s *strref_hash; int num_strings; strref_t *pr_xtstr; + int float_promoted; ///< for PR_Sprintf //@} /// \name memory map diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index 27c3f9c50..3ea2c3bd5 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -280,12 +280,15 @@ PR_BoundsCheck (progs_t *pr, int addr, etype_t type) #define OPB (*op_b) #define OPC (*op_c) +#define OPA_double_var (*((double *) (op_a))) +#define OPB_double_var (*((double *) (op_b))) +#define OPC_double_var (*((double *) (op_c))) + /* This gets around the problem of needing to test for -0.0 but denormals causing exceptions (or wrong results for what we need) on the alpha. */ -#define FNZ(x) ((x).uinteger_var && (x).uinteger_var != 0x80000000u) - +#define FNZ(x) ((x).uinteger_var & ~0x80000000u) static int signal_hook (int sig, void *data) @@ -421,6 +424,9 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_PrintStatement (pr, st, 1); switch (st->op) { + case OP_ADD_D: + OPC_double_var = OPA_double_var + OPB_double_var; + break; case OP_ADD_F: OPC.float_var = OPA.float_var + OPB.float_var; break; @@ -437,6 +443,9 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_GetString (pr, OPB.string_var)); break; + case OP_SUB_D: + OPC_double_var = OPA_double_var - OPB_double_var; + break; case OP_SUB_F: OPC.float_var = OPA.float_var - OPB.float_var; break; @@ -446,12 +455,31 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) case OP_SUB_Q: QuatSubtract (OPA.quat_var, OPB.quat_var, OPC.quat_var); break; + case OP_MUL_D: + OPC_double_var = OPA_double_var * OPB_double_var; + break; case OP_MUL_F: OPC.float_var = OPA.float_var * OPB.float_var; break; case OP_MUL_V: OPC.float_var = DotProduct (OPA.vector_var, OPB.vector_var); break; + case OP_MUL_DV: + { + // avoid issues with the likes of x = x.x * x; + // makes for faster code, too + double scale = OPA_double_var; + VectorScale (OPB.vector_var, scale, OPC.vector_var); + } + break; + case OP_MUL_VD: + { + // avoid issues with the likes of x = x * x.x; + // makes for faster code, too + double scale = OPB_double_var; + VectorScale (OPA.vector_var, scale, OPC.vector_var); + } + break; case OP_MUL_FV: { // avoid issues with the likes of x = x.x * x; @@ -474,6 +502,22 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) case OP_MUL_QV: QuatMultVec (OPA.quat_var, OPB.vector_var, OPC.vector_var); break; + case OP_MUL_DQ: + { + // avoid issues with the likes of x = x.s * x; + // makes for faster code, too + double scale = OPA_double_var; + QuatScale (OPB.quat_var, scale, OPC.quat_var); + } + break; + case OP_MUL_QD: + { + // avoid issues with the likes of x = x * x.s; + // makes for faster code, too + double scale = OPB_double_var; + QuatScale (OPA.quat_var, scale, OPC.quat_var); + } + break; case OP_MUL_FQ: { // avoid issues with the likes of x = x.s * x; @@ -493,6 +537,9 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) case OP_CONJ_Q: QuatConj (OPA.quat_var, OPC.quat_var); break; + case OP_DIV_D: + OPC_double_var = OPA_double_var / OPB_double_var; + break; case OP_DIV_F: OPC.float_var = OPA.float_var / OPB.float_var; break; @@ -630,6 +677,9 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) case OP_STORE_Q: QuatCopy (OPA.quat_var, OPB.quat_var); break; + case OP_STORE_D: + OPB_double_var = OPA_double_var; + break; case OP_STOREP_F: case OP_STOREP_ENT: @@ -661,6 +711,14 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) ptr = pr->pr_globals + pointer; QuatCopy (OPA.quat_var, ptr->quat_var); break; + case OP_STOREP_D: + pointer = OPB.integer_var; + if (pr_boundscheck->int_val) { + PR_BoundsCheck (pr, pointer, ev_double); + } + ptr = pr->pr_globals + pointer; + *(double *) ptr = OPA_double_var; + break; case OP_ADDRESS: if (pr_boundscheck->int_val) { @@ -687,6 +745,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) case OP_ADDRESS_FN: case OP_ADDRESS_I: case OP_ADDRESS_P: + case OP_ADDRESS_D: OPC.integer_var = st->a; break; @@ -735,6 +794,19 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) ed = PROG_TO_EDICT (pr, OPA.entity_var); memcpy (&OPC, &ed->v[OPB.integer_var], 4 * sizeof (OPC)); break; + case OP_LOAD_D: + if (pr_boundscheck->int_val) { + if (OPA.entity_var < 0 + || OPA.entity_var >= pr->pr_edictareasize) + PR_RunError (pr, "Progs attempted to read an out of " + "bounds edict number"); + if (OPB.uinteger_var + 1 >= pr->progs->entityfields) + PR_RunError (pr, "Progs attempted to read an invalid " + "field in an edict"); + } + ed = PROG_TO_EDICT (pr, OPA.entity_var); + OPC_double_var = *(double *) (ed->v + OPB.integer_var); + break; case OP_LOADB_F: case OP_LOADB_S: @@ -766,6 +838,14 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) ptr = pr->pr_globals + pointer; QuatCopy (ptr->quat_var, OPC.quat_var); break; + case OP_LOADB_D: + pointer = OPA.integer_var + OPB.integer_var; + if (pr_boundscheck->int_val) { + PR_BoundsCheck (pr, pointer, ev_double); + } + ptr = pr->pr_globals + pointer; + OPC_double_var = *(double *) ptr; + break; case OP_LOADBI_F: case OP_LOADBI_S: @@ -797,6 +877,14 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) ptr = pr->pr_globals + pointer; QuatCopy (ptr->quat_var, OPC.quat_var); break; + case OP_LOADBI_D: + pointer = OPA.integer_var + (short) st->b; + if (pr_boundscheck->int_val) { + PR_BoundsCheck (pr, pointer, ev_quat); + } + ptr = pr->pr_globals + pointer; + OPC_double_var = *(double *) ptr; + break; case OP_LEA: pointer = OPA.integer_var + OPB.integer_var; @@ -838,6 +926,14 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) ptr = pr->pr_globals + pointer; QuatCopy (OPA.quat_var, ptr->quat_var); break; + case OP_STOREB_D: + pointer = OPB.integer_var + OPC.integer_var; + if (pr_boundscheck->int_val) { + PR_BoundsCheck (pr, pointer, ev_quat); + } + ptr = pr->pr_globals + pointer; + *(double *) ptr = OPA_double_var; + break; case OP_STOREBI_F: case OP_STOREBI_S: @@ -869,6 +965,14 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) ptr = pr->pr_globals + pointer; QuatCopy (OPA.quat_var, ptr->quat_var); break; + case OP_STOREBI_D: + pointer = OPB.integer_var + (short) st->c; + if (pr_boundscheck->int_val) { + PR_BoundsCheck (pr, pointer, ev_quat); + } + ptr = pr->pr_globals + pointer; + *(double *) ptr = OPA_double_var; + break; case OP_PUSH_F: case OP_PUSH_FLD: @@ -1322,20 +1426,19 @@ op_call: case OP_MUL_I: OPC.integer_var = OPA.integer_var * OPB.integer_var; break; -/* - case OP_DIV_VF: - { - float temp = 1.0f / OPB.float_var; - VectorScale (OPA.vector_var, temp, OPC.vector_var); - } - break; -*/ case OP_DIV_I: OPC.integer_var = OPA.integer_var / OPB.integer_var; break; case OP_MOD_I: OPC.integer_var = OPA.integer_var % OPB.integer_var; break; + case OP_MOD_D: + { + double a = OPA_double_var; + double b = OPB_double_var; + OPC_double_var = a - b * trunc (a / b); + } + break; case OP_MOD_F: { float a = OPA.float_var; @@ -1432,6 +1535,41 @@ op_call: st->b * 4); break; + case OP_GE_D: + OPC.float_var = OPA_double_var >= OPB_double_var; + break; + case OP_LE_D: + OPC.float_var = OPA_double_var <= OPB_double_var; + break; + case OP_GT_D: + OPC.float_var = OPA_double_var > OPB_double_var; + break; + case OP_LT_D: + OPC.float_var = OPA_double_var < OPB_double_var; + break; + case OP_NOT_D: + OPC.integer_var = (op_a[0].integer_var + || (op_a[1].integer_var & ~0x80000000u)); + break; + case OP_EQ_D: + OPC.integer_var = OPA_double_var == OPB_double_var; + break; + case OP_NE_D: + OPC.integer_var = OPA_double_var != OPB_double_var; + break; + case OP_CONV_ID: + OPC_double_var = OPA.integer_var; + break; + case OP_CONV_DI: + OPC.integer_var = OPA_double_var; + break; + case OP_CONV_FD: + OPC_double_var = OPA.float_var; + break; + case OP_CONV_DF: + OPC.float_var = OPA_double_var; + break; + // LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized /* case OP_BOUNDCHECK: diff --git a/libs/gamecode/pr_opcode.c b/libs/gamecode/pr_opcode.c index 9e970c781..a2a344a1e 100644 --- a/libs/gamecode/pr_opcode.c +++ b/libs/gamecode/pr_opcode.c @@ -61,6 +61,7 @@ VISIBLE int pr_type_size[ev_type_count] = { 1, // ev_integer 1, // ev_uinteger 0, // ev_short value in opcode + 2, // ev_double }; VISIBLE const char *pr_type_name[ev_type_count] = { @@ -102,6 +103,10 @@ VISIBLE opcode_t pr_opcodes[] = { "%Va", }, + {"*", "mul.d", OP_MUL_D, false, + ev_double, ev_double, ev_double, + PROG_VERSION, + }, {"*", "mul.f", OP_MUL_F, false, ev_float, ev_float, ev_float, PROG_ID_VERSION, @@ -118,6 +123,14 @@ VISIBLE opcode_t pr_opcodes[] = { ev_vector, ev_float, ev_vector, PROG_ID_VERSION, }, + {"*", "mul.dv", OP_MUL_DV, false, + ev_double, ev_vector, ev_vector, + PROG_ID_VERSION, + }, + {"*", "mul.vd", OP_MUL_VD, false, + ev_vector, ev_double, ev_vector, + PROG_ID_VERSION, + }, {"*", "mul.q", OP_MUL_Q, false, ev_quat, ev_quat, ev_quat, PROG_VERSION, @@ -130,6 +143,14 @@ VISIBLE opcode_t pr_opcodes[] = { ev_quat, ev_float, ev_quat, PROG_VERSION, }, + {"*", "mul.dq", OP_MUL_DQ, false, + ev_double, ev_quat, ev_quat, + PROG_VERSION, + }, + {"*", "mul.qd", OP_MUL_QD, false, + ev_quat, ev_double, ev_quat, + PROG_VERSION, + }, {"*", "mul.qv", OP_MUL_QV, false, ev_quat, ev_vector, ev_vector, PROG_VERSION, @@ -145,7 +166,19 @@ VISIBLE opcode_t pr_opcodes[] = { ev_float, ev_float, ev_float, PROG_ID_VERSION, }, + {"/", "div.d", OP_DIV_D, false, + ev_double, ev_double, ev_double, + PROG_VERSION, + }, + {"%", "mod.d", OP_MOD_D, false, + ev_double, ev_double, ev_double, + PROG_VERSION, + }, + {"+", "add.d", OP_ADD_D, false, + ev_double, ev_double, ev_double, + PROG_VERSION, + }, {"+", "add.f", OP_ADD_F, false, ev_float, ev_float, ev_float, PROG_ID_VERSION, @@ -163,6 +196,10 @@ VISIBLE opcode_t pr_opcodes[] = { PROG_VERSION, }, + {"-", "sub.d", OP_SUB_D, false, + ev_double, ev_double, ev_double, + PROG_VERSION, + }, {"-", "sub.f", OP_SUB_F, false, ev_float, ev_float, ev_float, PROG_ID_VERSION, @@ -176,6 +213,10 @@ VISIBLE opcode_t pr_opcodes[] = { PROG_VERSION, }, + {"==", "eq.d", OP_EQ_D, false, + ev_double, ev_double, ev_integer, + PROG_VERSION, + }, {"==", "eq.f", OP_EQ_F, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION, @@ -201,6 +242,10 @@ VISIBLE opcode_t pr_opcodes[] = { PROG_ID_VERSION, }, + {"!=", "ne.d", OP_NE_D, false, + ev_double, ev_double, ev_integer, + PROG_VERSION, + }, {"!=", "ne.f", OP_NE_F, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION, @@ -226,10 +271,18 @@ VISIBLE opcode_t pr_opcodes[] = { PROG_ID_VERSION, }, + {"<=", "le.d", OP_LE_D, false, + ev_double, ev_double, ev_integer, + PROG_VERSION, + }, {"<=", "le.f", OP_LE_F, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION, }, + {">=", "ge.d", OP_GE_D, false, + ev_double, ev_double, ev_integer, + PROG_VERSION, + }, {">=", "ge.f", OP_GE_F, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION, @@ -242,10 +295,18 @@ VISIBLE opcode_t pr_opcodes[] = { ev_string, ev_string, ev_integer, PROG_VERSION, }, + {"<", "lt.d", OP_LT_D, false, + ev_double, ev_double, ev_integer, + PROG_VERSION, + }, {"<", "lt.f", OP_LT_F, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION, }, + {">", "gt.d", OP_GT_D, false, + ev_double, ev_double, ev_integer, + PROG_VERSION, + }, {">", "gt.f", OP_GT_F, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION, @@ -264,6 +325,11 @@ VISIBLE opcode_t pr_opcodes[] = { PROG_ID_VERSION, "%Ga.%Gb(%Ec), %gc",//FIXME %E more flexible? }, + {".", "load.d", OP_LOAD_D, false, + ev_entity, ev_field, ev_double, + PROG_VERSION, + "%Ga.%Gb(%Ec), %gc", + }, {".", "load.v", OP_LOAD_V, false, ev_entity, ev_field, ev_vector, PROG_ID_VERSION, @@ -305,6 +371,11 @@ VISIBLE opcode_t pr_opcodes[] = { "%Ga.%Gb(%Ec), %gc", }, + {".", "loadb.d", OP_LOADB_D, false, + ev_pointer, ev_integer, ev_double, + PROG_VERSION, + "*(%Ga + %Gb), %gc", + }, {".", "loadb.f", OP_LOADB_F, false, ev_pointer, ev_integer, ev_float, PROG_VERSION, @@ -351,6 +422,11 @@ VISIBLE opcode_t pr_opcodes[] = { "*(%Ga + %Gb), %gc", }, + {".", "loadbi.d", OP_LOADBI_D, false, + ev_pointer, ev_short, ev_double, + PROG_VERSION, + "*(%Ga + %sb), %gc", + }, {".", "loadbi.f", OP_LOADBI_F, false, ev_pointer, ev_short, ev_float, PROG_VERSION, @@ -408,6 +484,11 @@ VISIBLE opcode_t pr_opcodes[] = { PROG_VERSION, "%Ga, %gc", }, + {"&", "address.d", OP_ADDRESS_D, false, + ev_double, ev_invalid, ev_pointer, + PROG_VERSION, + "%Ga, %gc", + }, {"&", "address.f", OP_ADDRESS_F, false, ev_float, ev_invalid, ev_pointer, PROG_VERSION, @@ -475,7 +556,32 @@ VISIBLE opcode_t pr_opcodes[] = { PROG_VERSION, "%Ga, %gc", }, + {"", "conv.id", OP_CONV_ID, false, + ev_integer, ev_invalid, ev_double, + PROG_VERSION, + "%Ga, %gc", + }, + {"", "conv.di", OP_CONV_DI, false, + ev_double, ev_invalid, ev_integer, + PROG_VERSION, + "%Ga, %gc", + }, + {"", "conv.fd", OP_CONV_FD, false, + ev_float, ev_invalid, ev_double, + PROG_VERSION, + "%Ga, %gc", + }, + {"", "conv.df", OP_CONV_DF, false, + ev_double, ev_invalid, ev_float, + PROG_VERSION, + "%Ga, %gc", + }, + {"=", "store.d", OP_STORE_D, true, + ev_double, ev_double, ev_invalid, + PROG_VERSION, + "%Ga, %gb", + }, {"=", "store.f", OP_STORE_F, true, ev_float, ev_float, ev_invalid, PROG_ID_VERSION, @@ -522,6 +628,11 @@ VISIBLE opcode_t pr_opcodes[] = { "%Ga, %gb", }, + {".=", "storep.d", OP_STOREP_D, true, + ev_double, ev_pointer, ev_invalid, + PROG_ID_VERSION, + "%Ga, *%Gb", + }, {".=", "storep.f", OP_STOREP_F, true, ev_float, ev_pointer, ev_invalid, PROG_ID_VERSION, @@ -568,6 +679,11 @@ VISIBLE opcode_t pr_opcodes[] = { "%Ga, *%Gb", }, + {".=", "storeb.d", OP_STOREB_D, true, + ev_double, ev_pointer, ev_integer, + PROG_VERSION, + "%Ga, *(%Gb + %Gc)", + }, {".=", "storeb.f", OP_STOREB_F, true, ev_float, ev_pointer, ev_integer, PROG_VERSION, @@ -614,6 +730,11 @@ VISIBLE opcode_t pr_opcodes[] = { "%Ga, *(%Gb + %Gc)", }, + {".=", "storebi.d", OP_STOREBI_D, true, + ev_double, ev_pointer, ev_short, + PROG_VERSION, + "%Ga, *(%Gb + %sc)", + }, {".=", "storebi.f", OP_STOREBI_F, true, ev_float, ev_pointer, ev_short, PROG_VERSION, @@ -672,6 +793,11 @@ VISIBLE opcode_t pr_opcodes[] = { "", }, + {"!", "not.d", OP_NOT_D, false, + ev_double, ev_invalid, ev_integer, + PROG_VERSION, + "%Ga, %gc", + }, {"!", "not.f", OP_NOT_F, false, ev_float, ev_invalid, ev_integer, PROG_ID_VERSION, diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index b0edefa63..684551fda 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -70,6 +70,7 @@ struct strref_s { #define FMT_ADDSIGN (1<<3) #define FMT_ADDBLANK (1<<4) #define FMT_HEX (1<<5) +#define FMT_LONG (1<<6) typedef struct fmt_item_s { byte type; @@ -81,6 +82,7 @@ typedef struct fmt_item_s { int integer_var; unsigned uinteger_var; float float_var; + double double_var; } data; struct fmt_item_s *next; } fmt_item_t; @@ -596,11 +598,19 @@ I_DoPrint (dstring_t *result, fmt_item_t *formatting) break; case 'f': dstring_appendstr (tmp, "f"); - PRINT (float); + if (current->flags & FMT_LONG) { + PRINT (double); + } else { + PRINT (float); + } break; case 'g': dstring_appendstr (tmp, "g"); - PRINT (float); + if (current->flags & FMT_LONG) { + PRINT (double); + } else { + PRINT (float); + } break; default: break; @@ -650,7 +660,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, int fmt_count = 0; if (!name) - name = "PF_InternalSprintf"; + name = "PR_Sprintf"; *fi = new_fmt_item (); c = l = format; @@ -742,12 +752,19 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, fi = &(*fi)->next; break; case 'f': - // float + // float or double case 'g': - // float, no trailing zeroes, trim "." if nothing - // after + // float or double, no trailing zeroes, trim "." + // if nothing after (*fi)->type = *c; - (*fi)->data.float_var = P_FLOAT (pr, fmt_count); + if (pr->float_promoted) { + (*fi)->flags |= FMT_LONG; + (*fi)->data.double_var + = P_DOUBLE (pr, fmt_count); + } else { + (*fi)->data.float_var + = P_FLOAT (pr, fmt_count); + } fmt_count++; (*fi)->next = new_fmt_item (); diff --git a/libs/ruamoko/rua_math.c b/libs/ruamoko/rua_math.c index 0cc5e5636..167db865f 100644 --- a/libs/ruamoko/rua_math.c +++ b/libs/ruamoko/rua_math.c @@ -42,55 +42,55 @@ #include "rua_internal.h" static void -bi_sin (progs_t *pr) +bi_sinf (progs_t *pr) { R_FLOAT (pr) = sinf (P_FLOAT (pr, 0)); } static void -bi_cos (progs_t *pr) +bi_cosf (progs_t *pr) { R_FLOAT (pr) = cosf (P_FLOAT (pr, 0)); } static void -bi_tan (progs_t *pr) +bi_tanf (progs_t *pr) { R_FLOAT (pr) = tanf (P_FLOAT (pr, 0)); } static void -bi_asin (progs_t *pr) +bi_asinf (progs_t *pr) { R_FLOAT (pr) = asinf (P_FLOAT (pr, 0)); } static void -bi_acos (progs_t *pr) +bi_acosf (progs_t *pr) { R_FLOAT (pr) = acosf (P_FLOAT (pr, 0)); } static void -bi_atan (progs_t *pr) +bi_atanf (progs_t *pr) { R_FLOAT (pr) = atanf (P_FLOAT (pr, 0)); } static void -bi_atan2 (progs_t *pr) +bi_atan2f (progs_t *pr) { R_FLOAT (pr) = atan2f (P_FLOAT (pr, 0), P_FLOAT (pr, 1)); } static void -bi_log (progs_t *pr) +bi_logf (progs_t *pr) { R_FLOAT (pr) = logf (P_FLOAT (pr, 0)); } static void -bi_log2 (progs_t *pr) +bi_log2f (progs_t *pr) { #ifdef HAVE_LOG2F R_FLOAT (pr) = log2f (P_FLOAT (pr, 0)); @@ -100,95 +100,238 @@ bi_log2 (progs_t *pr) } static void -bi_log10 (progs_t *pr) +bi_log10f (progs_t *pr) { R_FLOAT (pr) = log10f (P_FLOAT (pr, 0)); } static void -bi_pow (progs_t *pr) +bi_powf (progs_t *pr) { R_FLOAT (pr) = powf (P_FLOAT (pr, 0), P_FLOAT (pr, 1)); } static void -bi_sqrt (progs_t *pr) +bi_sqrtf (progs_t *pr) { R_FLOAT (pr) = sqrtf (P_FLOAT (pr, 0)); } static void -bi_cbrt (progs_t *pr) +bi_cbrtf (progs_t *pr) { R_FLOAT (pr) = cbrtf (P_FLOAT (pr, 0)); } static void -bi_hypot (progs_t *pr) +bi_hypotf (progs_t *pr) { R_FLOAT (pr) = hypotf (P_FLOAT (pr, 0), P_FLOAT (pr, 1)); } static void -bi_sinh (progs_t *pr) +bi_sinhf (progs_t *pr) { R_FLOAT (pr) = sinhf (P_FLOAT (pr, 0)); } static void -bi_cosh (progs_t *pr) +bi_coshf (progs_t *pr) { R_FLOAT (pr) = coshf (P_FLOAT (pr, 0)); } static void -bi_tanh (progs_t *pr) +bi_tanhf (progs_t *pr) { R_FLOAT (pr) = tanhf (P_FLOAT (pr, 0)); } static void -bi_asinh (progs_t *pr) +bi_asinhf (progs_t *pr) { double y = P_FLOAT (pr, 0); R_FLOAT (pr) = logf (y + sqrtf (y * y + 1)); } static void -bi_acosh (progs_t *pr) +bi_acoshf (progs_t *pr) { double y = P_FLOAT (pr, 0); R_FLOAT (pr) = logf (y + sqrtf (y * y - 1)); } static void -bi_atanh (progs_t *pr) +bi_atanhf (progs_t *pr) { double y = P_FLOAT (pr, 0); R_FLOAT (pr) = logf ((1 + y) / (1 - y)) / 2; } +static void +bi_sin (progs_t *pr) +{ + R_DOUBLE (pr) = sin (P_DOUBLE (pr, 0)); +} + +static void +bi_cos (progs_t *pr) +{ + R_DOUBLE (pr) = cos (P_DOUBLE (pr, 0)); +} + +static void +bi_tan (progs_t *pr) +{ + R_DOUBLE (pr) = tan (P_DOUBLE (pr, 0)); +} + +static void +bi_asin (progs_t *pr) +{ + R_DOUBLE (pr) = asin (P_DOUBLE (pr, 0)); +} + +static void +bi_acos (progs_t *pr) +{ + R_DOUBLE (pr) = acos (P_DOUBLE (pr, 0)); +} + +static void +bi_atan (progs_t *pr) +{ + R_DOUBLE (pr) = atan (P_DOUBLE (pr, 0)); +} + +static void +bi_atan2 (progs_t *pr) +{ + R_DOUBLE (pr) = atan2 (P_DOUBLE (pr, 0), P_DOUBLE (pr, 1)); +} + +static void +bi_log (progs_t *pr) +{ + R_DOUBLE (pr) = log (P_DOUBLE (pr, 0)); +} + +static void +bi_log2 (progs_t *pr) +{ + R_DOUBLE (pr) = log (P_DOUBLE (pr, 0)) / M_LOG2E; +} + +static void +bi_log10 (progs_t *pr) +{ + R_DOUBLE (pr) = log10 (P_DOUBLE (pr, 0)); +} + +static void +bi_pow (progs_t *pr) +{ + R_DOUBLE (pr) = pow (P_DOUBLE (pr, 0), P_DOUBLE (pr, 1)); +} + +static void +bi_sqrt (progs_t *pr) +{ + R_DOUBLE (pr) = sqrt (P_DOUBLE (pr, 0)); +} + +static void +bi_cbrt (progs_t *pr) +{ + R_DOUBLE (pr) = cbrt (P_DOUBLE (pr, 0)); +} + +static void +bi_hypot (progs_t *pr) +{ + R_DOUBLE (pr) = hypot (P_DOUBLE (pr, 0), P_DOUBLE (pr, 1)); +} + +static void +bi_sinh (progs_t *pr) +{ + R_DOUBLE (pr) = sinh (P_DOUBLE (pr, 0)); +} + +static void +bi_cosh (progs_t *pr) +{ + R_DOUBLE (pr) = cosh (P_DOUBLE (pr, 0)); +} + +static void +bi_tanh (progs_t *pr) +{ + R_DOUBLE (pr) = tanh (P_DOUBLE (pr, 0)); +} + +static void +bi_asinh (progs_t *pr) +{ + double y = P_DOUBLE (pr, 0); + R_DOUBLE (pr) = log (y + sqrt (y * y + 1)); +} + +static void +bi_acosh (progs_t *pr) +{ + double y = P_DOUBLE (pr, 0); + R_DOUBLE (pr) = log (y + sqrt (y * y - 1)); +} + +static void +bi_atanh (progs_t *pr) +{ + double y = P_DOUBLE (pr, 0); + R_DOUBLE (pr) = log ((1 + y) / (1 - y)) / 2; +} + static builtin_t builtins[] = { - {"sin", bi_sin, -1}, - {"cos", bi_cos, -1}, - {"tan", bi_tan, -1}, - {"asin", bi_asin, -1}, - {"acos", bi_acos, -1}, - {"atan", bi_atan, -1}, - {"atan2", bi_atan2, -1}, - {"log", bi_log, -1}, - {"log2", bi_log2, -1}, - {"log10", bi_log10, -1}, - {"pow", bi_pow, -1}, - {"sqrt", bi_sqrt, -1}, - {"cbrt", bi_cbrt, -1}, - {"hypot", bi_hypot, -1}, - {"sinh", bi_sinh, -1}, - {"cosh", bi_cosh, -1}, - {"tanh", bi_tanh, -1}, - {"asinh", bi_asinh, -1}, - {"acosh", bi_acosh, -1}, - {"atanh", bi_atanh, -1}, + {"sin|f", bi_sinf, -1}, + {"cos|f", bi_cosf, -1}, + {"tan|f", bi_tanf, -1}, + {"asin|f", bi_asinf, -1}, + {"acos|f", bi_acosf, -1}, + {"atan|f", bi_atanf, -1}, + {"atan2|f", bi_atan2f, -1}, + {"log|f", bi_logf, -1}, + {"log2|f", bi_log2f, -1}, + {"log10|f", bi_log10f, -1}, + {"pow|f", bi_powf, -1}, + {"sqrt|f", bi_sqrtf, -1}, + {"cbrt|f", bi_cbrtf, -1}, + {"hypot|f", bi_hypotf, -1}, + {"sinh|f", bi_sinhf, -1}, + {"cosh|f", bi_coshf, -1}, + {"tanh|f", bi_tanhf, -1}, + {"asinh|f", bi_asinhf, -1}, + {"acosh|f", bi_acoshf, -1}, + {"atanh|f", bi_atanhf, -1}, + {"sin|d", bi_sin, -1}, + {"cos|d", bi_cos, -1}, + {"tan|d", bi_tan, -1}, + {"asin|d", bi_asin, -1}, + {"acos|d", bi_acos, -1}, + {"atan|d", bi_atan, -1}, + {"atan2|d", bi_atan2, -1}, + {"log|d", bi_log, -1}, + {"log2|d", bi_log2, -1}, + {"log10|d", bi_log10, -1}, + {"pow|d", bi_pow, -1}, + {"sqrt|d", bi_sqrt, -1}, + {"cbrt|d", bi_cbrt, -1}, + {"hypot|d", bi_hypot, -1}, + {"sinh|d", bi_sinh, -1}, + {"cosh|d", bi_cosh, -1}, + {"tanh|d", bi_tanh, -1}, + {"asinh|d", bi_asinh, -1}, + {"acosh|d", bi_acosh, -1}, + {"atanh|d", bi_atanh, -1}, {0} }; diff --git a/nq/include/sv_progs.h b/nq/include/sv_progs.h index e1b8d4e4a..07a8c8f7c 100644 --- a/nq/include/sv_progs.h +++ b/nq/include/sv_progs.h @@ -210,6 +210,11 @@ extern progs_t sv_pr_state; #define SVentity(e,f) SVFIELD (e, f, entity) #define SVvector(e,f) SVFIELD (e, f, vector) #define SVinteger(e,f) SVFIELD (e, f, integer) +#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 typedef struct edict_leaf_s { struct edict_leaf_s *next; diff --git a/nq/source/sv_progs.c b/nq/source/sv_progs.c index c289b6e44..7e98550d4 100644 --- a/nq/source/sv_progs.c +++ b/nq/source/sv_progs.c @@ -361,6 +361,9 @@ set_address (sv_def_t *def, void *address) case ev_quat: *(float **)def->field = (float *) address; break; + case ev_double: + *(double **)def->field = (double *) address; + break; case ev_string: case ev_entity: case ev_field: diff --git a/qw/include/sv_progs.h b/qw/include/sv_progs.h index ca96f7de5..18bdde503 100644 --- a/qw/include/sv_progs.h +++ b/qw/include/sv_progs.h @@ -195,6 +195,11 @@ extern progs_t sv_pr_state; #define SVentity(e,f) SVFIELD (e, f, entity) #define SVvector(e,f) SVFIELD (e, f, vector) #define SVinteger(e,f) SVFIELD (e, f, integer) +#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 typedef struct edict_leaf_s { struct edict_leaf_s *next; diff --git a/qw/source/sv_progs.c b/qw/source/sv_progs.c index cad265b11..e4856f69b 100644 --- a/qw/source/sv_progs.c +++ b/qw/source/sv_progs.c @@ -371,6 +371,9 @@ set_address (sv_def_t *def, void *address) case ev_quat: *(float **)def->field = (float *) address; break; + case ev_double: + *(double **)def->field = (double *) address; + break; case ev_string: case ev_entity: case ev_field: diff --git a/ruamoko/include/math.h b/ruamoko/include/math.h index fad67a9de..d6ad33342 100644 --- a/ruamoko/include/math.h +++ b/ruamoko/include/math.h @@ -60,17 +60,20 @@ /** Returns \a f, rounded down to the next lower integer */ -@extern float floor (float f); +@extern @overload float floor (float f); +@extern @overload double floor (double f); /** Returns \a f, rounded up to the next highest integer */ -@extern float ceil (float f); +@extern @overload float ceil (float f); +@extern @overload double ceil (double f); /** Returns the absolute value of \a f */ -@extern float fabs (float f); +@extern @overload float fabs (float f); +@extern @overload double fabs (double f); //\} ///\name Exponentials and Logarithms @@ -78,32 +81,38 @@ /** Returns the natural log of \a x. */ -@extern float log (float x); +@extern @overload float log (float x); +@extern @overload double log (double x); /** Returns the base-2 log of \a x. */ -@extern float log2 (float x); +@extern @overload float log2 (float x); +@extern @overload double log2 (double x); /** Returns the base-10 log of \a x. */ -@extern float log10 (float x); +@extern @overload float log10 (float x); +@extern @overload double log10 (double x); /** Returns \a x to the \a y power */ -@extern float pow (float x, float y); +@extern @overload float pow (float x, float y); +@extern @overload double pow (double x, double y); /** Returns the square root of \a x */ -@extern float sqrt (float x); +@extern @overload float sqrt (float x); +@extern @overload double sqrt (double x); /** Returns the cube root of \a x */ -@extern float cbrt (float x); +@extern @overload float cbrt (float x); +@extern @overload double cbrt (double x); //\} ///\name Trigonometric functions @@ -112,40 +121,52 @@ /** Returns the sine of \a x. */ -@extern float sin (float x); +@extern @overload float sin (float x); +@extern @overload double sin (double x); /** Returns the cosine of \a x. */ -@extern float cos (float x); +@extern @overload float cos (float x); +@extern @overload double cos (double x); /** Returns the tangent of \a x. */ -@extern float tan (float x); +@extern @overload float tan (float x); +@extern @overload double tan (double x); /** Returns the arcsine of \a x. */ -@extern float asin (float x); +@extern @overload float asin (float x); +@extern @overload double asin (double x); /** Returns the arccosine of \a x. */ -@extern float acos (float x); +@extern @overload float acos (float x); +@extern @overload double acos (double x); /** Returns the arctangent of \a x. */ -@extern float atan (float x); -@extern float atan2 (float y, float x); +@extern @overload float atan (float x); +@extern @overload double atan (double x); + +/** + Returns the arctangent of \a y / \a x preserving the quadrant. +*/ +@extern @overload float atan2 (float y, float x); +@extern @overload double atan2 (double y, double x); /** Returns the length of the hypotenuse of a right triangle with sides \a x and \a y. That is, this function returns sqrt (\a x*\a x + \a y*\a y). */ -@extern float hypot (float x, float y); +@extern @overload float hypot (float x, float y); +@extern @overload double hypot (double x, double y); //\} ///\name Hyperbolic functions @@ -153,32 +174,38 @@ /** Returns the hyperbolic sine of \a x */ -@extern float sinh (float x); +@extern @overload float sinh (float x); +@extern @overload double sinh (double x); /** Returns the hyperbolic cosine of \a x */ -@extern float cosh (float x); +@extern @overload float cosh (float x); +@extern @overload double cosh (double x); /** Returns the hyperbolic tangent of \a x */ -@extern float tanh (float x); +@extern @overload float tanh (float x); +@extern @overload double tanh (double x); /** Returns the area hyperbolic sine of \a x */ -@extern float asinh (float x); +@extern @overload float asinh (float x); +@extern @overload double asinh (double x); /** Returns the area hyperbolic cosine of \a x */ -@extern float acosh (float x); +@extern @overload float acosh (float x); +@extern @overload double acosh (double x); /** Returns the area hyperbolic tangent of \a x */ -@extern float atanh (float x); +@extern @overload float atanh (float x); +@extern @overload double atanh (double x); //\} ///\name Vector Functions diff --git a/ruamoko/lib/math.r b/ruamoko/lib/math.r index 8d0c51342..80db2b710 100644 --- a/ruamoko/lib/math.r +++ b/ruamoko/lib/math.r @@ -34,3 +34,27 @@ float (float x) atanh = #0; float (float x) sqrt = #0; float (float x) cbrt = #0; float (float x, float y) hypot = #0; + +double (double v) floor = #0; +double (double v) ceil = #0; +double (double f) fabs = #0; +double (double x) sin = #0; +double (double x) cos = #0; +double (double x) tan = #0; +double (double x) asin = #0; +double (double x) acos = #0; +double (double x) atan = #0; +double (double y, double x) atan2 = #0; +double (double x) log = #0; +double (double x) log2 = #0; +double (double x) log10 = #0; +double (double x, double y) pow = #0; +double (double x) sinh = #0; +double (double x) cosh = #0; +double (double x) tanh = #0; +double (double x) asinh = #0; +double (double x) acosh = #0; +double (double x) atanh = #0; +double (double x) sqrt = #0; +double (double x) cbrt = #0; +double (double x, double y) hypot = #0; diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index d83610b7f..b11e93c2c 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -174,6 +174,7 @@ typedef struct ex_value_s { etype_t lltype; union { const char *string_val; ///< string constant + float double_val; ///< double constant float float_val; ///< float constant float vector_val[3]; ///< vector constant int entity_val; ///< entity constant @@ -397,6 +398,15 @@ expr_t *new_name_expr (const char *name); expr_t *new_string_expr (const char *string_val); const char *expr_string (expr_t *e) __attribute__((pure)); +/** Create a new double constant expression node. + + \param double_val The double constant being represented. + \return The new double constant expression node + (expr_t::e::double_val). +*/ +expr_t *new_double_expr (double double_val); +double expr_double (expr_t *e) __attribute__((pure)); + /** Create a new float constant expression node. \param float_val The float constant being represented. diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index d064de8ca..d6a43816e 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -98,6 +98,7 @@ typedef struct { extern type_t type_invalid; extern type_t type_void; extern type_t type_string; +extern type_t type_double; extern type_t type_float; extern type_t type_vector; extern type_t type_entity; @@ -153,6 +154,7 @@ const char *type_get_encoding (const type_t *type); int is_void (const type_t *type) __attribute__((pure)); int is_enum (const type_t *type) __attribute__((pure)); int is_integral (const type_t *type) __attribute__((pure)); +int is_double (const type_t *type) __attribute__((pure)); int is_float (const type_t *type) __attribute__((pure)); int is_scalar (const type_t *type) __attribute__((pure)); int is_vector (const type_t *type) __attribute__((pure)); diff --git a/tools/qfcc/include/value.h b/tools/qfcc/include/value.h index 883af01e0..aaac286b7 100644 --- a/tools/qfcc/include/value.h +++ b/tools/qfcc/include/value.h @@ -40,6 +40,7 @@ struct ex_value_s; struct type_s; struct ex_value_s *new_string_val (const char *string_val); +struct ex_value_s *new_double_val (double double_val); struct ex_value_s *new_float_val (float float_val); struct ex_value_s *new_vector_val (const float *vector_val); struct ex_value_s *new_entity_val (int entity_val); diff --git a/tools/qfcc/source/constfold.c b/tools/qfcc/source/constfold.c index 817703945..3cba7f467 100644 --- a/tools/qfcc/source/constfold.c +++ b/tools/qfcc/source/constfold.c @@ -48,6 +48,7 @@ #include "qfcc.h" #include "strpool.h" #include "type.h" +#include "value.h" #include "qc-parse.h" typedef expr_t *(*operation_t) (int op, expr_t *e, expr_t *e1, expr_t *e2); @@ -163,6 +164,40 @@ convert_to_float (expr_t *e) } } +static expr_t * +convert_to_double (expr_t *e) +{ + if (get_type (e) == &type_double) + return e; + + switch (e->type) { + case ex_value: + switch (e->e.value->lltype) { + case ev_integer: + e->e.value = new_double_val (expr_integer (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); + } +} + static expr_t * do_op_float (int op, expr_t *e, expr_t *e1, expr_t *e2) { @@ -292,6 +327,111 @@ do_op_float (int op, expr_t *e, expr_t *e1, expr_t *e2) return e; } +static expr_t * +do_op_double (int op, expr_t *e, expr_t *e1, expr_t *e2) +{ + double d1, d2; + expr_t *conv; + type_t *type = &type_double; + static int valid[] = { + '=', '+', '-', '*', '/', '%', + LT, GT, LE, GE, EQ, NE, 0 + }; + + if (!valid_op (op, valid)) + return error (e1, "invalid operator for double"); + + if (op == '=' || op == PAS) { + if ((type = get_type (e1)) != &type_double) { + //FIXME optimize casting a constant + e->e.expr.e2 = e2 = cf_cast_expr (type, e2); + } else if ((conv = convert_to_double (e2)) != e2) { + e->e.expr.e2 = e2 = conv; + } + } else { + if ((conv = convert_to_double (e1)) != e1) { + e->e.expr.e1 = e1 = conv; + } + if ((conv = convert_to_double (e2)) != e2) { + e->e.expr.e2 = e2 = conv; + } + } + if (is_compare (op) || is_logic (op)) { + type = &type_integer; + } + e->e.expr.type = type; + + if (op == '*' && is_constant (e1) && expr_double (e1) == 1) + return e2; + if (op == '*' && is_constant (e2) && expr_double (e2) == 1) + return e1; + if (op == '*' && is_constant (e1) && expr_double (e1) == 0) + return e1; + if (op == '*' && is_constant (e2) && expr_double (e2) == 0) + return e2; + if (op == '/' && is_constant (e2) && expr_double (e2) == 1) + return e1; + if (op == '/' && is_constant (e2) && expr_double (e2) == 0) + return error (e, "division by zero"); + if (op == '/' && is_constant (e1) && expr_double (e1) == 0) + return e1; + if (op == '+' && is_constant (e1) && expr_double (e1) == 0) + return e2; + if (op == '+' && is_constant (e2) && expr_double (e2) == 0) + return e1; + if (op == '-' && is_constant (e2) && expr_double (e2) == 0) + return e1; + + if (op == '=' || !is_constant (e1) || !is_constant (e2)) + return e; + + d1 = expr_double (e1); + d2 = expr_double (e2); + + switch (op) { + case '+': + e = new_double_expr (d1 + d2); + break; + case '-': + e = new_double_expr (d1 - d2); + break; + case '*': + e = new_double_expr (d1 * d2); + break; + case '/': + if (!d2) + return error (e1, "divide by zero"); + e = new_double_expr (d1 / d2); + break; + case '%': + e = new_double_expr ((int)d1 % (int)d2); + break; + case LT: + e = new_integer_expr (d1 < d2); + break; + case GT: + e = new_integer_expr (d1 > d2); + break; + case LE: + e = new_integer_expr (d1 <= d2); + break; + case GE: + e = new_integer_expr (d1 >= d2); + break; + case EQ: + e = new_integer_expr (d1 == d2); + break; + case NE: + e = new_integer_expr (d1 != d2); + break; + default: + internal_error (e1, 0); + } + e->file = e1->file; + e->line = e1->line; + return e; +} + static expr_t * do_op_vector (int op, expr_t *e, expr_t *e1, expr_t *e2) { @@ -884,11 +1024,15 @@ do_op_compound (int op, expr_t *e, expr_t *e1, expr_t *e2) return do_op_struct (op, e, e1, e2); if (is_scalar (t1) && is_scalar (t2)) { if (is_enum (t1)) { - if (t2->type == ev_float) + if (t2->type == ev_double) + return do_op_float (op, e, e1, e2); + if (t2->type == ev_double) return do_op_float (op, e, e1, e2); return do_op_integer (op, e, e1, e2); } if (is_enum (t2)) { + if (t1->type == ev_double) + return do_op_double (op, e, e1, e2); if (t1->type == ev_float) return do_op_float (op, e, e1, e2); return do_op_integer (op, e, e1, e2); @@ -947,6 +1091,7 @@ static operation_t op_void[ev_type_count] = { do_op_invalid, // ev_integer do_op_invalid, // ev_uinteger do_op_invalid, // ev_short + do_op_invalid, // ev_double do_op_invalid, // ev_invalid }; @@ -963,6 +1108,7 @@ static operation_t op_string[ev_type_count] = { do_op_invalid, // ev_integer do_op_invalid, // ev_uinteger do_op_invalid, // ev_short + do_op_invalid, // ev_double do_op_invalid, // ev_invalid }; @@ -979,6 +1125,7 @@ static operation_t op_float[ev_type_count] = { do_op_float, // ev_integer do_op_float, // ev_uinteger do_op_float, // ev_short + do_op_double, // ev_double do_op_invalid, // ev_invalid }; @@ -995,6 +1142,7 @@ static operation_t op_vector[ev_type_count] = { do_op_vector, // ev_integer do_op_vector, // ev_uinteger do_op_vector, // ev_short + do_op_vector, // ev_double do_op_invalid, // ev_invalid }; @@ -1011,6 +1159,7 @@ static operation_t op_entity[ev_type_count] = { do_op_invalid, // ev_integer do_op_invalid, // ev_uinteger do_op_invalid, // ev_short + do_op_invalid, // ev_double do_op_invalid, // ev_invalid }; @@ -1027,6 +1176,7 @@ static operation_t op_field[ev_type_count] = { do_op_invalid, // ev_integer do_op_invalid, // ev_uinteger do_op_invalid, // ev_short + do_op_invalid, // ev_double do_op_invalid, // ev_invalid }; @@ -1043,6 +1193,7 @@ static operation_t op_func[ev_type_count] = { do_op_func, // ev_integer do_op_func, // ev_uinteger do_op_func, // ev_short + do_op_func, // ev_double do_op_func, // ev_invalid }; @@ -1059,6 +1210,7 @@ static operation_t op_pointer[ev_type_count] = { do_op_pointer, // ev_integer do_op_pointer, // ev_uinteger do_op_pointer, // ev_short + do_op_pointer, // ev_double do_op_pointer, // ev_invalid }; @@ -1075,6 +1227,7 @@ static operation_t op_quaternion[ev_type_count] = { do_op_quaternion, // ev_integer do_op_quaternion, // ev_uinteger do_op_quaternion, // ev_short + do_op_quaternion, // ev_double do_op_invalid, // ev_invalid }; @@ -1091,6 +1244,7 @@ static operation_t op_integer[ev_type_count] = { do_op_integer, // ev_integer do_op_uinteger, // ev_uinteger do_op_integer, // ev_short + do_op_double, // ev_double do_op_invalid, // ev_invalid }; @@ -1107,6 +1261,7 @@ static operation_t op_uinteger[ev_type_count] = { do_op_uinteger, // ev_integer do_op_uinteger, // ev_uinteger do_op_uinteger, // ev_short + do_op_double, // ev_double do_op_invalid, // ev_invalid }; @@ -1123,6 +1278,24 @@ static operation_t op_short[ev_type_count] = { do_op_integer, // ev_integer do_op_uinteger, // ev_uinteger do_op_short, // ev_short + do_op_double, // ev_double + do_op_invalid, // ev_invalid +}; + +static operation_t op_double[ev_type_count] = { + do_op_invalid, // ev_void + do_op_invalid, // ev_string + do_op_float, // ev_float + do_op_vector, // ev_vector + do_op_invalid, // ev_entity + do_op_invalid, // ev_field + do_op_invalid, // ev_func + do_op_invalid, // ev_pointer + do_op_quaternion, // ev_quaternion + do_op_integer, // ev_integer + do_op_uinteger, // ev_uinteger + do_op_short, // ev_short + do_op_double, // ev_double do_op_invalid, // ev_invalid }; @@ -1139,6 +1312,7 @@ static operation_t op_compound[ev_type_count] = { do_op_compound, // ev_integer do_op_compound, // ev_uinteger do_op_compound, // ev_short + do_op_compound, // ev_double do_op_compound, // ev_invalid }; @@ -1155,6 +1329,7 @@ static operation_t *do_op[ev_type_count] = { op_integer, // ev_integer op_uinteger, // ev_uinteger op_short, // ev_short + op_double, // ev_double op_compound, // ev_invalid }; @@ -1203,13 +1378,15 @@ static expr_t * uop_float (int op, expr_t *e, expr_t *e1) { static int valid[] = { '+', '-', '!', '~', 'C', 0 }; + type_t *type; if (!valid_op (op, valid)) return error (e1, "invalid unary operator for float: %s", get_op_string (op)); if (op == '+') return e1; - if (op == 'C' && get_type (e) != &type_integer) + type = get_type (e); + if (op == 'C' && type != &type_integer && type != &type_double) return error (e1, "invalid cast of float"); if (!is_constant (e1)) return e; @@ -1222,7 +1399,11 @@ uop_float (int op, expr_t *e, expr_t *e1) case '~': return new_float_expr (~(int) expr_float (e1)); case 'C': - return new_integer_expr (expr_float (e1)); + if (type == &type_integer) { + return new_integer_expr (expr_float (e1)); + } else { + return new_double_expr (expr_float (e1)); + } } internal_error (e, "float unary op blew up"); } @@ -1420,6 +1601,38 @@ uop_short (int op, expr_t *e, expr_t *e1) internal_error (e, "short unary op blew up"); } +static expr_t * +uop_double (int op, expr_t *e, expr_t *e1) +{ + static int valid[] = { '+', '-', '!', 'C', 0 }; + type_t *type; + + if (!valid_op (op, valid)) + return error (e1, "invalid unary operator for double: %s", + get_op_string (op)); + if (op == '+') + return e1; + type = get_type (e); + if (op == 'C' && type != &type_integer && type != &type_float) + return error (e1, "invalid cast of double"); + if (!is_constant (e1)) + return e; + switch (op) { + case '-': + return new_double_expr (-expr_double (e1)); + case '!': + print_type (get_type (e)); + return new_integer_expr (!expr_double (e1)); + case 'C': + if (type == &type_integer) { + return new_integer_expr (expr_double (e1)); + } else { + return new_float_expr (expr_double (e1)); + } + } + internal_error (e, "float unary op blew up"); +} + static expr_t * uop_compound (int op, expr_t *e, expr_t *e1) { @@ -1446,6 +1659,7 @@ static unaryop_t do_unary_op[ev_type_count] = { uop_integer, // ev_integer uop_uinteger, // ev_uinteger uop_short, // ev_short + uop_double, // ev_double uop_compound, // ev_invalid }; @@ -1487,7 +1701,7 @@ fold_constants (expr_t *e) if (t1 >= ev_type_count || t2 >= ev_type_count || !do_op[t1] || !do_op[t1][t2]) - internal_error (e, "invalid type"); + internal_error (e, "invalid type %d %d", t1, t2); return do_op[t1][t2] (op, e, e1, e2); } return e; diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index b98cc7b99..675488e93 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -438,6 +438,9 @@ print_value (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) case ev_string: label = va ("\\\"%s\\\"", quote_string (e->e.value->v.string_val)); break; + case ev_double: + label = va ("f %g", e->e.value->v.double_val); + break; case ev_float: label = va ("f %g", e->e.value->v.float_val); break; diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 4970cc7cd..0773e0a8f 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -611,6 +611,15 @@ new_string_expr (const char *string_val) return e; } +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; +} + expr_t * new_float_expr (float float_val) { @@ -845,6 +854,23 @@ is_float_val (expr_t *e) return 0; } +double +expr_double (expr_t *e) +{ + if (e->type == ex_nil) + return 0; + if (e->type == ex_value && e->e.value->lltype == ev_double) + return e->e.value->v.double_val; + if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const + && e->e.symbol->type->type == ev_double) + return e->e.symbol->s.value->v.double_val; + if (e->type == ex_symbol && e->e.symbol->sy_type == sy_var + && e->e.symbol->s.def->constant + && is_double (e->e.symbol->s.def->type)) + return D_FLOAT (e->e.symbol->s.def); + internal_error (e, "not a double constant"); +} + float expr_float (expr_t *e) { @@ -1276,6 +1302,9 @@ test_expr (expr_t *e) } new = new_float_expr (0); break; + case ev_double: + new = new_double_expr (0); + break; case ev_vector: new = new_vector_expr (zero); break; @@ -1610,6 +1639,8 @@ unary_expr (int op, expr_t *e) case ev_func: case ev_pointer: internal_error (e, "type check failed!"); + case ev_double: + return new_double_expr (-expr_double (e)); case ev_float: return new_float_expr (-expr_float (e)); case ev_vector: @@ -1676,6 +1707,8 @@ unary_expr (int op, expr_t *e) case ev_string: s = expr_string (e); return new_integer_expr (!s || !s[0]); + case ev_double: + return new_integer_expr (!expr_double (e)); case ev_float: return new_integer_expr (!expr_float (e)); case ev_vector: @@ -1735,6 +1768,7 @@ unary_expr (int op, expr_t *e) case ev_func: case ev_pointer: case ev_vector: + case ev_double: return error (e, "invalid type for unary ~"); case ev_float: return new_float_expr (~(int) expr_float (e)); diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index 1b234e9e4..0c9fea604 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -333,6 +333,7 @@ static keyword_t at_keywords[] = { // be supported (sanely) by v6 progs. static keyword_t qf_keywords[] = { {"quaternion", TYPE, &type_quaternion}, + {"double", TYPE, &type_double}, {"int", TYPE, &type_integer }, {"unsigned", TYPE, &type_integer },//FIXME {"function", TYPE, &type_function }, diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index c4c92f254..cd49b3970 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -87,6 +87,8 @@ operand_string (operand_t *op) case ev_string: return va ("\"%s\"", quote_string (op->o.value->v.string_val)); + case ev_double: + return va ("%g", op->o.value->v.double_val); case ev_float: return va ("%g", op->o.value->v.float_val); case ev_vector: @@ -159,6 +161,9 @@ print_operand (operand_t *op) case ev_string: printf ("\"%s\"", op->o.value->v.string_val); break; + case ev_double: + printf ("%g", op->o.value->v.double_val); + break; case ev_float: printf ("%g", op->o.value->v.float_val); break; diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index d99a89cc4..81bd21ef9 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -76,6 +76,7 @@ type_t type_quaternion = { ev_quat, "quaternion" }; type_t type_integer = { ev_integer, "int" }; type_t type_uinteger = { ev_uinteger, "uint" }; type_t type_short = { ev_short, "short" }; +type_t type_double = { ev_double, "double" }; type_t *type_nil; type_t *type_default; @@ -101,6 +102,7 @@ type_t *ev_types[ev_type_count] = { &type_integer, &type_uinteger, &type_short, + &type_double, &type_invalid, }; @@ -180,6 +182,7 @@ free_type (type_t *type) case ev_integer: case ev_uinteger: case ev_short: + case ev_double: break; case ev_field: case ev_pointer: @@ -214,6 +217,7 @@ append_type (type_t *type, type_t *new) case ev_integer: case ev_uinteger: case ev_short: + case ev_double: internal_error (0, "append to basic type"); case ev_field: case ev_pointer: @@ -582,6 +586,9 @@ encode_type (dstring_t *encoding, const type_t *type) case ev_string: dasprintf (encoding, "*"); break; + case ev_double: + dasprintf (encoding, "d"); + break; case ev_float: dasprintf (encoding, "f"); break; @@ -685,6 +692,12 @@ is_integral (const type_t *type) return is_enum (type); } +int +is_double (const type_t *type) +{ + return type->type == ev_double; +} + int is_float (const type_t *type) { @@ -694,7 +707,7 @@ is_float (const type_t *type) int is_scalar (const type_t *type) { - return is_float (type) || is_integral (type); + return is_float (type) || is_integral (type) || is_double (type); } int @@ -830,6 +843,7 @@ type_size (const type_t *type) case ev_integer: case ev_uinteger: case ev_short: + case ev_double: case ev_type_count: return pr_type_size[type->type]; case ev_invalid: @@ -869,6 +883,7 @@ init_types (void) { static struct_def_t zero_struct[] = { {"string_val", &type_string}, + {"double_val", &type_double}, {"float_val", &type_float}, {"entity_val", &type_entity}, {"field_val", &type_field}, @@ -884,6 +899,7 @@ init_types (void) }; static struct_def_t param_struct[] = { {"string_val", &type_string}, + {"double_val", &type_double}, {"float_val", &type_float}, {"vector_val", &type_vector}, {"entity_val", &type_entity}, @@ -982,6 +998,7 @@ chain_initial_types (void) chain_type (&type_integer); chain_type (&type_uinteger); chain_type (&type_short); + chain_type (&type_double); } chain_type (&type_param); diff --git a/tools/qfcc/source/value.c b/tools/qfcc/source/value.c index 29d6eabed..4f1ae9f82 100644 --- a/tools/qfcc/source/value.c +++ b/tools/qfcc/source/value.c @@ -132,6 +132,16 @@ new_string_val (const char *string_val) return find_value (&val); } +ex_value_t * +new_double_val (double double_val) +{ + ex_value_t val; + memset (&val, 0, sizeof (val)); + set_val_type (&val, &type_double); + val.v.double_val = double_val; + return find_value (&val); +} + ex_value_t * new_float_val (float float_val) {