From 291f920e2ad6cd1223368652b7185670101799fb Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Sep 2024 20:19:17 +0900 Subject: [PATCH] [qfcc] Parse vector literals correctly It turned out that for v6 progs (due to lack of double or long) weren't getting correctly parsed vector literals: incorrect "implicit" flag and then a lot of brittleness around constant value conversions. --- tools/qfcc/include/expr.h | 9 ++- tools/qfcc/include/options.h | 1 + tools/qfcc/source/constfold.c | 36 ++++----- tools/qfcc/source/expr.c | 131 ++++++++++++++++++++++++++++---- tools/qfcc/source/expr_binary.c | 2 +- tools/qfcc/source/options.c | 1 + tools/qfcc/source/qc-lex.l | 39 +++++----- tools/qfcc/source/qp-lex.l | 2 +- tools/qfcc/source/statements.c | 4 +- tools/qfcc/source/switch.c | 4 +- 10 files changed, 173 insertions(+), 56 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 256755d86..7b514926e 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -652,7 +652,7 @@ double expr_double (const expr_t *e) __attribute__((pure)); \return The new float constant expression node (expr_t::e::float_val). */ -const expr_t *new_float_expr (float float_val); +const expr_t *new_float_expr (float float_val, bool implicit); float expr_float (const expr_t *e) __attribute__((pure)); /** Create a new vector constant expression node. @@ -737,6 +737,7 @@ unsigned expr_uint (const expr_t *e) __attribute__((pure)); const expr_t *new_long_expr (pr_long_t long_val, bool implicit); pr_long_t expr_long (const expr_t *e) __attribute__((pure)); +pr_ulong_t expr_ulong (const expr_t *e) __attribute__((pure)); const expr_t *new_ulong_expr (pr_ulong_t ulong_val); /** Create a new short constant expression node. @@ -749,7 +750,8 @@ const expr_t *new_short_expr (short short_val); short expr_short (const expr_t *e) __attribute__((pure)); unsigned short expr_ushort (const expr_t *e) __attribute__((pure)); -int expr_integral (const expr_t *e) __attribute__((pure)); +pr_long_t expr_integral (const expr_t *e) __attribute__((pure)); +double expr_floating (const expr_t *e) __attribute__((pure)); bool is_error (const expr_t *e) __attribute__((pure)); @@ -817,8 +819,11 @@ int is_quaternion_val (const expr_t *e) __attribute__((pure)); int is_int_val (const expr_t *e) __attribute__((pure)); int is_uint_val (const expr_t *e) __attribute__((pure)); int is_short_val (const expr_t *e) __attribute__((pure)); +int is_long_val (const expr_t *e) __attribute__((pure)); +int is_ulong_val (const expr_t *e) __attribute__((pure)); int is_double_val (const expr_t *e) __attribute__((pure)); int is_integral_val (const expr_t *e) __attribute__((pure)); +int is_floating_val (const expr_t *e) __attribute__((pure)); int is_pointer_val (const expr_t *e) __attribute__((pure)); int is_math_val (const expr_t *e) __attribute__((pure)); diff --git a/tools/qfcc/include/options.h b/tools/qfcc/include/options.h index 0fdf2ef85..dbf8400ab 100644 --- a/tools/qfcc/include/options.h +++ b/tools/qfcc/include/options.h @@ -53,6 +53,7 @@ typedef struct { bool assoc_float_add; // allow fp addition to be associative bool assoc_float_mul; // allow fp multiplication to be associative bool no_double; // double fp type is not supported + bool no_int; // int type is not supported bool help; } code_options_t; diff --git a/tools/qfcc/source/constfold.c b/tools/qfcc/source/constfold.c index 617a8456e..91d1dac2b 100644 --- a/tools/qfcc/source/constfold.c +++ b/tools/qfcc/source/constfold.c @@ -69,7 +69,7 @@ static const expr_t * cmp_result_expr (int result) { if (is_float (type_default)) { - return new_float_expr (result); + return new_float_expr (result, false); } else { return new_int_expr (result, false); } @@ -224,36 +224,36 @@ do_op_float (int op, const expr_t *e, const expr_t *e1, const expr_t *e2) const expr_t *new = 0; switch (op) { case '+': - new = new_float_expr (f1 + f2); + new = new_float_expr (f1 + f2, false); break; case '-': - new = new_float_expr (f1 - f2); + new = new_float_expr (f1 - f2, false); break; case '*': - new = new_float_expr (f1 * f2); + new = new_float_expr (f1 * f2, false); break; case '/': if (!f2) return error (e1, "divide by zero"); - new = new_float_expr (f1 / f2); + new = new_float_expr (f1 / f2, false); break; case '&': - new = new_float_expr ((int)f1 & (int)f2); + new = new_float_expr ((int)f1 & (int)f2, false); break; case '|': - new = new_float_expr ((int)f1 | (int)f2); + new = new_float_expr ((int)f1 | (int)f2, false); break; case '^': - new = new_float_expr ((int)f1 ^ (int)f2); + new = new_float_expr ((int)f1 ^ (int)f2, false); break; case '%': - new = new_float_expr ((int)f1 % (int)f2); + new = new_float_expr ((int)f1 % (int)f2, false); break; case QC_SHL: - new = new_float_expr ((int)f1 << (int)f2); + new = new_float_expr ((int)f1 << (int)f2, false); break; case QC_SHR: - new = new_float_expr ((int)f1 >> (int)f2); + new = new_float_expr ((int)f1 >> (int)f2, false); break; case QC_AND: new = cmp_result_expr (f1 && f2); @@ -414,7 +414,7 @@ do_op_vector (int op, const expr_t *e, const expr_t *e1, const expr_t *e2) } else if (op == QC_DOT && is_vector(get_type (e2))) { //e->expr.type = &type_float; } else if (op == '/' && !is_constant (e1)) { - e2 = fold_constants (binary_expr ('/', new_float_expr (1), e2)); + e2 = fold_constants (binary_expr ('/', new_float_expr (1, false), e2)); e = fold_constants (binary_expr ('*', e1, e2)); } else { //e->expr.type = &type_vector; @@ -475,7 +475,7 @@ do_op_vector (int op, const expr_t *e, const expr_t *e1, const expr_t *e2) new = new_vector_expr (v); break; case QC_DOT: - new = new_float_expr (DotProduct (v1, v2)); + new = new_float_expr (DotProduct (v1, v2), false); break; case QC_SCALE: VectorScale (v1, v2[0], v); @@ -561,7 +561,7 @@ do_op_quaternion (int op, const expr_t *e, const expr_t *e1, const expr_t *e2) else e->expr.type = &type_float; } else if (op == '/' && !is_constant (e1)) { - e2 = fold_constants (binary_expr ('/', new_float_expr (1), e2)); + e2 = fold_constants (binary_expr ('/', new_float_expr (1, false), e2)); e = fold_constants (binary_expr ('*', e1, e2)); } else { e->expr.type = &type_quaternion; @@ -1314,12 +1314,12 @@ uop_float (int op, const expr_t *e, const expr_t *e1) return e; switch (op) { case '-': - return new_float_expr (-expr_float (e1)); + return new_float_expr (-expr_float (e1), false); case '!': print_type (get_type (e)); return cmp_result_expr (!expr_float (e1)); case '~': - return new_float_expr (~(int) expr_float (e1)); + return new_float_expr (~(int) expr_float (e1), false); case 'C': if (is_int(type)) { return new_int_expr (expr_float (e1), false); @@ -1472,7 +1472,7 @@ uop_int (int op, const expr_t *e, const expr_t *e1) case '~': return new_int_expr (~expr_int (e1), false); case 'C': - return new_float_expr (expr_int (e1)); + return new_float_expr (expr_int (e1), false); } internal_error (e, "int unary op blew up"); } @@ -1548,7 +1548,7 @@ uop_double (int op, const expr_t *e, const expr_t *e1) if (is_int(type)) { return new_int_expr (expr_double (e1), false); } else { - return new_float_expr (expr_double (e1)); + return new_float_expr (expr_double (e1), false); } } internal_error (e, "float unary op blew up"); diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index cd98e923e..081613982 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -93,7 +93,7 @@ convert_name (const expr_t *e) } if (!strcmp (sym->name, "__INFINITY__") && current_func) { - return new_float_expr (INFINITY); + return new_float_expr (INFINITY, false); } if (!strcmp (sym->name, "__FILE__") && current_func) { @@ -784,9 +784,9 @@ new_double_expr (double double_val, bool implicit) } const expr_t * -new_float_expr (float float_val) +new_float_expr (float float_val, bool implicit) { - return new_value_expr (new_float_val (float_val), false); + return new_value_expr (new_float_val (float_val), implicit); } const expr_t * @@ -843,6 +843,54 @@ new_long_expr (pr_long_t long_val, bool implicit) return new_value_expr (new_long_val (long_val), implicit); } +int +is_long_val (const expr_t *e) +{ + if (e->type == ex_nil) { + return 1; + } + if (e->type == ex_value && e->value->lltype == ev_long) { + return 1; + } + if (e->type == ex_symbol && e->symbol->sy_type == sy_const) { + auto type = e->symbol->type; + if (is_long (type)) { + return 1; + } + } + if (e->type == ex_def && e->def->constant) { + auto type = e->def->type; + if (is_long (type)) { + return 1; + } + } + return 0; +} + +int +is_ulong_val (const expr_t *e) +{ + if (e->type == ex_nil) { + return 1; + } + if (e->type == ex_value && e->value->lltype == ev_ulong) { + return 1; + } + if (e->type == ex_symbol && e->symbol->sy_type == sy_const) { + auto type = e->symbol->type; + if (is_ulong (type)) { + return 1; + } + } + if (e->type == ex_def && e->def->constant) { + auto type = e->def->type; + if (is_ulong (type)) { + return 1; + } + } + return 0; +} + pr_long_t expr_long (const expr_t *e) { @@ -861,6 +909,18 @@ new_ulong_expr (pr_ulong_t ulong_val) return new_value_expr (new_ulong_val (ulong_val), false); } +pr_ulong_t +expr_ulong (const expr_t *e) +{ + if (e->type == ex_nil) { + return 0; + } + if (e->type == ex_value && e->value->lltype == ev_ulong) { + return e->value->ulong_val; + } + internal_error (e, "not a ulong constant"); +} + const expr_t * new_short_expr (short short_val) { @@ -1093,13 +1153,17 @@ is_int_val (const expr_t *e) if (e->type == ex_value && e->value->lltype == ev_int) { return 1; } - if (e->type == ex_symbol && e->symbol->sy_type == sy_const - && is_integral (e->symbol->type)) { - return 1; + if (e->type == ex_symbol && e->symbol->sy_type == sy_const) { + auto type = e->symbol->type; + if (!is_long (type) && !is_ulong (type) && is_integral (type)) { + return 1; + } } - if (e->type == ex_def && e->def->constant - && is_integral (e->def->type)) { - return 1; + if (e->type == ex_def && e->def->constant) { + auto type = e->def->type; + if (!is_long (type) && !is_ulong (type) && is_integral (type)) { + return 1; + } } return 0; } @@ -1239,11 +1303,31 @@ is_integral_val (const expr_t *e) if (is_short_val (e)) { return 1; } + if (is_long_val (e)) { + return 1; + } + if (is_ulong_val (e)) { + return 1; + } } return 0; } int +is_floating_val (const expr_t *e) +{ + if (is_constant (e)) { + if (is_float_val (e)) { + return 1; + } + if (is_double_val (e)) { + return 1; + } + } + return 0; +} + +pr_long_t expr_integral (const expr_t *e) { if (is_constant (e)) { @@ -1256,6 +1340,26 @@ expr_integral (const expr_t *e) if (is_short_val (e)) { return expr_short (e); } + if (is_long_val (e)) { + return expr_long (e); + } + if (is_ulong_val (e)) { + return expr_ulong (e); + } + } + internal_error (e, "not an integral constant"); +} + +double +expr_floating (const expr_t *e) +{ + if (is_constant (e)) { + if (is_float_val (e)) { + return expr_float (e); + } + if (is_double_val (e)) { + return expr_double (e); + } } internal_error (e, "not an integral constant"); } @@ -1647,8 +1751,8 @@ convert_from_bool (const expr_t *e, const type_t *type) expr_t *enum_zero, *enum_one; if (is_float (type)) { - one = new_float_expr (1); - zero = new_float_expr (0); + one = new_float_expr (1, false); + zero = new_float_expr (0, false); } else if (is_int (type)) { one = new_int_expr (1, false); zero = new_int_expr (0, false); @@ -1835,7 +1939,7 @@ unary_expr (int op, const expr_t *e) case ev_double: return new_double_expr (-expr_double (e), e->implicit); case ev_float: - return new_float_expr (-expr_float (e)); + return new_float_expr (-expr_float (e), e->implicit); case ev_vector: VectorNegate (expr_vector (e), v); return new_vector_expr (v); @@ -2047,7 +2151,8 @@ unary_expr (int op, const expr_t *e) case ev_double: return error (e, "invalid type for unary ~"); case ev_float: - return new_float_expr (~(int) expr_float (e)); + return new_float_expr (~(int) expr_float (e), + e->implicit); case ev_quaternion: QuatConj (expr_vector (e), q); return new_vector_expr (q); diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index 406986568..5e673206b 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -985,7 +985,7 @@ inverse_multiply (int op, const expr_t *e1, const expr_t *e2) { // There is no vector/float or quaternion/float instruction and adding // one would mean the engine would have to do 1/f every time - auto one = new_float_expr (1); + auto one = new_float_expr (1, false); return binary_expr ('*', e1, binary_expr ('/', one, e2)); } diff --git a/tools/qfcc/source/options.c b/tools/qfcc/source/options.c index 476467687..9cb489f05 100644 --- a/tools/qfcc/source/options.c +++ b/tools/qfcc/source/options.c @@ -861,6 +861,7 @@ DecodeArgs (int argc, char **argv) if (options.code.progsversion == PROG_ID_VERSION) { options.code.promote_float = false; options.code.no_double = true; + options.code.no_int = true; cpp_define ("__VERSION6__=1"); if (!options_user_set.code.crc) { options.code.crc = true; diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index b8804fb08..71ef294ba 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -593,10 +593,10 @@ parse_number (const rua_tok_t *tok, yyscan_t scanner) if (fp) { if (expl == suff_float) { - return new_float_expr (fvalue); + return new_float_expr (fvalue, false); } else { if (options.code.no_double) { - return new_float_expr (fvalue); + return new_float_expr (fvalue, expl == suff_implicit); } else { return new_double_expr (fvalue, expl == suff_implicit); } @@ -609,7 +609,7 @@ parse_number (const rua_tok_t *tok, yyscan_t scanner) } else if (expl == suff_unsigned_long) { return new_ulong_expr (lvalue); } else if (expl == suff_float) { - return new_float_expr (lvalue); + return new_float_expr (lvalue, false); } else if (expl == suff_double) { return new_double_expr (lvalue, false); } else { @@ -688,11 +688,12 @@ parse_vector (const rua_tok_t *tok, yyscan_t scanner) bool fp = false; for (int i = 0; i < width; i++) { if (!components[i]->implicit) { - error (0, "explict numeric constant in vector literal." - " Suggest suffix after closing '."); + warning (0, "explicit numeric constant in vector literal." + " Suggest suffix after closing '."); return 0; } - fp |= is_double (get_type (components[i])); + auto t = get_type (components[i]); + fp |= is_double (t) || is_float (t); } // end points at the final ' and thus any suffix is after that @@ -721,10 +722,10 @@ parse_vector (const rua_tok_t *tok, yyscan_t scanner) if (expl == suff_float) { for (int i = 0; i < width; i++) { auto c = components[i]; - if (is_double (get_type (c))) { - data.f[i] = expr_double (c); + if (is_floating_val (c)) { + data.f[i] = expr_floating (c); } else { - data.f[i] = expr_long (c); + data.f[i] = expr_integral (c); } if (negate[i]) { data.f[i] = -data.f[i]; @@ -734,10 +735,10 @@ parse_vector (const rua_tok_t *tok, yyscan_t scanner) } else if (expl == suff_double) { for (int i = 0; i < width; i++) { auto c = components[i]; - if (is_double (get_type (c))) { - data.d[i] = expr_double (c); + if (is_floating_val (c)) { + data.d[i] = expr_floating (c); } else { - data.d[i] = expr_long (c); + data.d[i] = expr_integral (c); } if (negate[i]) { data.d[i] = -data.d[i]; @@ -748,10 +749,10 @@ parse_vector (const rua_tok_t *tok, yyscan_t scanner) if (fp) { for (int i = 0; i < width; i++) { auto c = components[i]; - if (is_double (get_type (c))) { - data.f[i] = expr_double (c); + if (is_floating_val (c)) { + data.f[i] = expr_floating (c); } else { - data.f[i] = expr_long (c); + data.f[i] = expr_integral (c); } if (negate[i]) { data.f[i] = -data.f[i]; @@ -761,7 +762,11 @@ parse_vector (const rua_tok_t *tok, yyscan_t scanner) } else { for (int i = 0; i < width; i++) { auto c = components[i]; - data.i[i] = expr_long (c); + if (is_floating_val (c)) { + data.i[i] = expr_floating (c); + } else { + data.i[i] = expr_integral (c); + } if (negate[i]) { data.i[i] = -data.i[i]; } @@ -983,7 +988,7 @@ convert_long (const expr_t *value) if (f != v) { warning (0, "cannot represent value"); } - return new_float_expr (f); + return new_float_expr (f, true); } } diff --git a/tools/qfcc/source/qp-lex.l b/tools/qfcc/source/qp-lex.l index eaec1c31a..cb988ac7e 100644 --- a/tools/qfcc/source/qp-lex.l +++ b/tools/qfcc/source/qp-lex.l @@ -138,7 +138,7 @@ FRAMEID {ID}(\.{ID})* {FLOAT} { float f = strtof (yytext, 0); - yylval->expr = new_float_expr (f); + yylval->expr = new_float_expr (f, false); return VALUE; } diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 752a02ec4..08101cdf2 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -1057,7 +1057,7 @@ vector_call (sblock_t *sblock, const expr_t *earg, const expr_t *param, int ind, for (i = 0; i < 3; i++) { n = new_name_expr (names[i]); - v = new_float_expr (earg->value->vector_val[i]); + v = new_float_expr (earg->value->vector_val[i], false); a = assign_expr (field_expr (param, n), v); param = new_param_expr (get_type (earg), ind); //a->line = earg->line; @@ -1554,7 +1554,7 @@ statement_return (sblock_t *sblock, const expr_t *e) if (options.code.progsversion == PROG_ID_VERSION) { auto n = new_expr (); *n = *e; - n->retrn.ret_val = new_float_expr (0); + n->retrn.ret_val = new_float_expr (0, false); e = n; } } diff --git a/tools/qfcc/source/switch.c b/tools/qfcc/source/switch.c index a3fa5cf73..d1d18bdd9 100644 --- a/tools/qfcc/source/switch.c +++ b/tools/qfcc/source/switch.c @@ -143,9 +143,9 @@ case_label_expr (switch_block_t *switch_block, const expr_t *value) value = new_int_expr (expr_float (value), false); } else if (is_float (type) && is_integral (val_type)) { debug (value, "integeral label used in float switch"); - value = new_float_expr (expr_int (value)); + value = new_float_expr (expr_int (value), false); } else if (is_float (type) && is_float (val_type)) { - value = new_float_expr (expr_float (value)); + value = new_float_expr (expr_float (value), false); debug (value, "float label used in float switch"); } }