[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).
This commit is contained in:
Bill Currie 2023-08-26 22:57:11 +09:00
parent 8a0246c910
commit 29a57b7128
6 changed files with 62 additions and 52 deletions

View file

@ -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 = {

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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 ();