From 29a57b7128f1cda38544721b86ff7f838421de5c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 26 Aug 2023 22:57:11 +0900 Subject: [PATCH] [qfcc] Correct handling of 64-bit comparisons While the progs engine itself implements the instructions correctly, the opcode specs (and thus qfcc) treated the results as 32-bit (which was, really, a hidden fixme, it seems). --- libs/gamecode/opcodes.py | 3 +- tools/qfcc/source/constfold.c | 8 ++-- tools/qfcc/source/expr_binary.c | 75 +++++++++++++++++---------------- tools/qfcc/source/expr_bool.c | 9 ++-- tools/qfcc/source/expr_cast.c | 3 +- tools/qfcc/test/double.r | 16 +++---- 6 files changed, 62 insertions(+), 52 deletions(-) diff --git a/libs/gamecode/opcodes.py b/libs/gamecode/opcodes.py index 2b0d6f6bb..bff6ad7b9 100644 --- a/libs/gamecode/opcodes.py +++ b/libs/gamecode/opcodes.py @@ -155,11 +155,12 @@ compare_formats = { "mnemonic": "{op_cmp[ccc]}.{cmp_type[tt]}", "opname": "{op_cmp[ccc]}", "widths": "{ss+1}, {ss+1}, {ss+1}", - "types": "{cmp_types[tt]}, {cmp_types[tt]}, ev_int", + "types": "{cmp_types[tt]}, {cmp_types[tt]}, {res_types[tt & 2]}", "args": { "op_cmp": compare_ccc, "cmp_type": type_tt, "cmp_types": etype_tt, + "res_types": etype_tt, }, } compare2_formats = { diff --git a/tools/qfcc/source/constfold.c b/tools/qfcc/source/constfold.c index 1b88ff718..20e94918b 100644 --- a/tools/qfcc/source/constfold.c +++ b/tools/qfcc/source/constfold.c @@ -323,7 +323,7 @@ do_op_double (int op, expr_t *e, expr_t *e1, expr_t *e2) e->e.expr.e2 = e2 = conv; } if (is_compare (op) || is_logic (op)) { - type = &type_int; + type = int_type (get_type (e)); } e->e.expr.type = type; @@ -1736,8 +1736,10 @@ fold_constants (expr_t *e) t2 = extract_type (e2); if (t1 >= ev_type_count || t2 >= ev_type_count - || !do_op[t1] || !do_op[t1][t2]) - internal_error (e, "invalid type %d %d", t1, t2); + || !do_op[t1] || !do_op[t1][t2]) { + debug (e, "unhandled type %d %d", t1, t2); + return e; + } return do_op[t1][t2] (op, e, e1, e2); } return e; diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index 4e6434036..07bc75ebe 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -348,12 +348,12 @@ static expr_type_t int_double[] = { {'/', &type_double, &type_double, 0}, {'%', &type_double, &type_double, 0}, {MOD, &type_double, &type_double, 0}, - {EQ, &type_int, &type_double, 0}, - {NE, &type_int, &type_double, 0}, - {LE, &type_int, &type_double, 0}, - {GE, &type_int, &type_double, 0}, - {LT, &type_int, &type_double, 0}, - {GT, &type_int, &type_double, 0}, + {EQ, &type_long, &type_double, 0}, + {NE, &type_long, &type_double, 0}, + {LE, &type_long, &type_double, 0}, + {GE, &type_long, &type_double, 0}, + {LT, &type_long, &type_double, 0}, + {GT, &type_long, &type_double, 0}, {0, 0} }; @@ -526,12 +526,12 @@ static expr_type_t double_double[] = { {'/', &type_double}, {'%', &type_double}, {MOD, &type_double}, - {EQ, &type_int}, - {NE, &type_int}, - {LE, &type_int}, - {GE, &type_int}, - {LT, &type_int}, - {GT, &type_int}, + {EQ, &type_long}, + {NE, &type_long}, + {LE, &type_long}, + {GE, &type_long}, + {LT, &type_long}, + {GT, &type_long}, {0, 0} }; @@ -547,33 +547,33 @@ static expr_type_t long_long[] = { {MOD, &type_long}, {SHL, &type_long}, {SHR, &type_long}, - {EQ, &type_int}, - {NE, &type_int}, - {LE, &type_int}, - {GE, &type_int}, - {LT, &type_int}, - {GT, &type_int}, + {EQ, &type_long}, + {NE, &type_long}, + {LE, &type_long}, + {GE, &type_long}, + {LT, &type_long}, + {GT, &type_long}, {0, 0} }; static expr_type_t ulong_ulong[] = { - {'+', &type_long}, - {'-', &type_long}, - {'*', &type_long}, - {'/', &type_long}, - {'&', &type_long}, - {'|', &type_long}, - {'^', &type_long}, - {'%', &type_long}, - {MOD, &type_long}, - {SHL, &type_long}, - {SHR, &type_long}, - {EQ, &type_int}, - {NE, &type_int}, - {LE, &type_int}, - {GE, &type_int}, - {LT, &type_int}, - {GT, &type_int}, + {'+', &type_ulong}, + {'-', &type_ulong}, + {'*', &type_ulong}, + {'/', &type_ulong}, + {'&', &type_ulong}, + {'|', &type_ulong}, + {'^', &type_ulong}, + {'%', &type_ulong}, + {MOD, &type_ulong}, + {SHL, &type_ulong}, + {SHR, &type_ulong}, + {EQ, &type_long}, + {NE, &type_long}, + {LE, &type_long}, + {GE, &type_long}, + {LT, &type_long}, + {GT, &type_long}, {0, 0} }; @@ -908,7 +908,7 @@ double_compare (int op, expr_t *e1, expr_t *e2) e1 = cast_expr (&type_double, e1); } e = new_binary_expr (op, e1, e2); - e->e.expr.type = &type_int; + e->e.expr.type = &type_long; return e; } @@ -1221,6 +1221,9 @@ binary_expr (int op, expr_t *e1, expr_t *e2) // both widths are the same at this point if (t1->width > 1) { e = new_binary_expr (op, e1, e2); + if (is_compare (op)) { + t1 = int_type (t1); + } e->e.expr.type = t1; return e; } diff --git a/tools/qfcc/source/expr_bool.c b/tools/qfcc/source/expr_bool.c index 52d377b75..f4e1b52be 100644 --- a/tools/qfcc/source/expr_bool.c +++ b/tools/qfcc/source/expr_bool.c @@ -96,8 +96,10 @@ test_expr (expr_t *e) break; case ev_long: case ev_ulong: + e = new_alias_expr (&type_ivec2, e); + return new_horizontal_expr ('|', e, &type_int); case ev_ushort: - internal_error (e, "long not implemented"); + internal_error (e, "ushort not implemented"); case ev_uint: case ev_int: case ev_short: @@ -123,8 +125,9 @@ test_expr (expr_t *e) new = new_float_expr (0); break; case ev_double: - new = new_double_expr (0); - break; + new = expr_file_line (new_double_expr (0), e); + new = expr_file_line (binary_expr (NE, e, new), e); + return test_expr (new); case ev_vector: new = new_vector_expr (zero); break; diff --git a/tools/qfcc/source/expr_cast.c b/tools/qfcc/source/expr_cast.c index 3567f1f55..235fc33ca 100644 --- a/tools/qfcc/source/expr_cast.c +++ b/tools/qfcc/source/expr_cast.c @@ -138,7 +138,8 @@ cast_expr (type_t *dstType, expr_t *e) } if (is_constant (e) && is_math (dstType) && is_math (srcType)) { return cast_math (dstType, srcType, e); - } else if (is_integral (dstType) && is_integral (srcType)) { + } else if (is_integral (dstType) && is_integral (srcType) + && type_size (dstType) == type_size (srcType)) { c = new_alias_expr (dstType, e); } else if (is_scalar (dstType) && is_scalar (srcType)) { c = new_unary_expr ('C', e); diff --git a/tools/qfcc/test/double.r b/tools/qfcc/test/double.r index de0649b19..d3bd39307 100644 --- a/tools/qfcc/test/double.r +++ b/tools/qfcc/test/double.r @@ -6,7 +6,7 @@ union { int i[2]; } type_pun; -int +long test_format () { int fail = 0; @@ -17,10 +17,10 @@ test_format () return fail; } -int +long test_constant () { - int fail = 0; + long fail = 0; double a, b, c, d, e; a = 1; b = 2.0; @@ -40,10 +40,10 @@ double greater_equal = 3; double less_equal = 5; double greater = 5; -int +long test_copare () { - int fail = 0; + long fail = 0; fail |= !(less < greater); fail |= (less > greater); @@ -75,10 +75,10 @@ test_copare () return fail; } -int +long test_ops () { - int fail = 0; + long fail = 0; double a = 6.25, b = 2.375; double c; @@ -98,7 +98,7 @@ test_ops () int main () { - int fail = 0; + long fail = 0; fail |= test_format (); fail |= test_constant (); fail |= test_ops ();