From 5c9ba80d3aeffff872ba982da01263ef94e8c499 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 22 Sep 2024 15:19:59 +0900 Subject: [PATCH] [qfcc] Rewrite unary_expr to be more maintainable Result type and constant handling is now table-driven, resulting in the removal of seven switch statements (and thus a lot less hassle when extending types or expressions). Also, (u)long and (u)short are fully implemented. In addition, other than result type handing for boolean results, any back-end specific implementation is now in the back-end. --- tools/qfcc/include/expr.h | 1 + tools/qfcc/include/value.h | 1 + tools/qfcc/source/dot_expr.c | 3 + tools/qfcc/source/expr.c | 6 + tools/qfcc/source/expr_binary.c | 6 +- tools/qfcc/source/expr_unary.c | 768 ++++++++++++++++++-------------- tools/qfcc/source/statements.c | 72 ++- tools/qfcc/source/value.c | 10 + 8 files changed, 507 insertions(+), 360 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 0bac39688..91bd777c0 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -750,6 +750,7 @@ const expr_t *new_ulong_expr (pr_ulong_t ulong_val); */ const expr_t *new_short_expr (short short_val); short expr_short (const expr_t *e) __attribute__((pure)); +const expr_t *new_ushort_expr (unsigned short short_val); unsigned short expr_ushort (const expr_t *e) __attribute__((pure)); pr_long_t expr_integral (const expr_t *e) __attribute__((pure)); diff --git a/tools/qfcc/include/value.h b/tools/qfcc/include/value.h index 58e7a38f8..715956235 100644 --- a/tools/qfcc/include/value.h +++ b/tools/qfcc/include/value.h @@ -60,6 +60,7 @@ 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_ushort_val (unsigned short ushort_val); struct ex_value_s *new_nil_val (const struct type_s *type); struct ex_value_s *new_type_value (const struct type_s *type, const struct pr_type_s *data); diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index fae6c2371..461453f17 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -101,6 +101,9 @@ get_op_string (int op) case QC_DOT: return "@dot"; case QC_WEDGE: return "@wedge"; case QC_REGRESSIVE: return "@regressive"; + case QC_REVERSE: return "@reverse"; + case QC_DUAL: return "@dual"; + case QC_UNDUAL: return "@undual"; case QC_AT_FIELD: return "@field"; case QC_AT_POINTER: return "@pointer"; case QC_AT_ARRAY: return "@array"; diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index f3c5007d8..0e30a7d59 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -952,6 +952,12 @@ new_short_expr (short short_val) return new_value_expr (new_short_val (short_val), false); } +const expr_t * +new_ushort_expr (unsigned short ushort_val) +{ + return new_value_expr (new_ushort_val (ushort_val), false); +} + bool is_error (const expr_t *e) { diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index f7802a64f..73d767630 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -40,9 +40,9 @@ typedef struct { int op; - type_t *result_type; - type_t *a_cast; - type_t *b_cast; + const type_t *result_type; + const type_t *a_cast; + const type_t *b_cast; const expr_t *(*process)(int op, const expr_t *e1, const expr_t *e2); bool (*commutative) (void); bool (*anticommute) (void); diff --git a/tools/qfcc/source/expr_unary.c b/tools/qfcc/source/expr_unary.c index ef6e28e38..5cae5ffdc 100644 --- a/tools/qfcc/source/expr_unary.c +++ b/tools/qfcc/source/expr_unary.c @@ -63,354 +63,434 @@ #include "tools/qfcc/include/type.h" #include "tools/qfcc/include/value.h" +typedef struct { + int op; + const type_t *result_type; + const expr_t *(*process)(const expr_t *e); + const expr_t *(*constant)(const expr_t *e); +} unary_type_t; + +static const expr_t * +string_not (const expr_t *e) +{ + const char *s = expr_string (e); + return new_int_expr (!s || !s[0], false); +} + +static const expr_t * +float_negate (const expr_t *e) +{ + return new_float_expr (-expr_float (e), e->implicit); +} + +static const expr_t * +float_not (const expr_t *e) +{ + return new_int_expr (!expr_float (e), false); +} + +static const expr_t * +float_bitnot (const expr_t *e) +{ + return new_float_expr (~(int) expr_float (e), false); +} + +static const expr_t * +vector_negate (const expr_t *e) +{ + vec3_t v; + + VectorNegate (expr_vector (e), v); + return new_vector_expr (v); +} + +static const expr_t * +vector_not (const expr_t *e) +{ + return new_int_expr (!VectorIsZero (expr_vector (e)), false); +} + +static const expr_t * +quat_negate (const expr_t *e) +{ + quat_t q; + + QuatNegate (expr_quaternion (e), q); + return new_vector_expr (q); +} + +static const expr_t * +pointer_deref (const expr_t *e) +{ + scoped_src_loc (e); + auto new = new_unary_expr ('.', e); + new->expr.type = get_type (e)->fldptr.type; + return new; +} + +static const expr_t * +quat_not (const expr_t *e) +{ + return new_int_expr (!QuatIsZero (expr_quaternion (e)), false); +} + +static const expr_t * +quat_conj (const expr_t *e) +{ + quat_t q; + + QuatConj (expr_vector (e), q); + return new_quaternion_expr (q); +} + +static const expr_t * +int_negate (const expr_t *e) +{ + return new_int_expr (-expr_int (e), false); +} + +static const expr_t * +int_not (const expr_t *e) +{ + return new_int_expr (!expr_int (e), e->implicit); +} + +static const expr_t * +int_bitnot (const expr_t *e) +{ + return new_int_expr (~expr_int (e), e->implicit); +} + +static const expr_t * +uint_negate (const expr_t *e) +{ + return new_uint_expr (-expr_uint (e)); +} + +static const expr_t * +uint_not (const expr_t *e) +{ + return new_uint_expr (!expr_uint (e)); +} + +static const expr_t * +uint_bitnot (const expr_t *e) +{ + return new_uint_expr (~expr_uint (e)); +} + +static const expr_t * +short_negate (const expr_t *e) +{ + return new_short_expr (-expr_short (e)); +} + +static const expr_t * +short_not (const expr_t *e) +{ + return new_short_expr (!expr_short (e)); +} + +static const expr_t * +short_bitnot (const expr_t *e) +{ + return new_short_expr (~expr_short (e)); +} + +static const expr_t * +ushort_negate (const expr_t *e) +{ + return new_ushort_expr (-expr_ushort (e)); +} + +static const expr_t * +ushort_not (const expr_t *e) +{ + return new_ushort_expr (!expr_ushort (e)); +} + +static const expr_t * +ushort_bitnot (const expr_t *e) +{ + return new_ushort_expr (~expr_ushort (e)); +} + +static const expr_t * +double_negate (const expr_t *e) +{ + return new_double_expr (-expr_double (e), e->implicit); +} + +static const expr_t * +double_not (const expr_t *e) +{ + return new_int_expr (!expr_double (e), false); +} + +static const expr_t * +double_bitnot (const expr_t *e) +{ + return new_double_expr (~(pr_long_t) expr_double (e), false); +} + +static const expr_t * +long_negate (const expr_t *e) +{ + return new_long_expr (-expr_long (e), e->implicit); +} + +static const expr_t * +long_not (const expr_t *e) +{ + return new_int_expr (!expr_long (e), false); +} + +static const expr_t * +long_bitnot (const expr_t *e) +{ + return new_long_expr (~expr_long (e), e->implicit); +} + +static const expr_t * +ulong_negate (const expr_t *e) +{ + return new_ulong_expr (-expr_ulong (e)); +} + +static const expr_t * +ulong_not (const expr_t *e) +{ + return new_int_expr (!expr_ulong (e), false); +} + +static const expr_t * +ulong_bitnot (const expr_t *e) +{ + return new_ulong_expr (~expr_ulong (e)); +} + +static unary_type_t string_u[] = { + { .op = '!', .result_type = &type_bool, .constant = string_not, }, + + {} +}; + +static unary_type_t float_u[] = { + { .op = '-', .result_type = &type_float, .constant = float_negate, }, + { .op = '!', .result_type = &type_bool, .constant = float_not, }, + { .op = '~', .result_type = &type_float, .constant = float_bitnot, }, + { .op = QC_REVERSE, .process = algebra_reverse, }, + { .op = QC_DUAL, .process = algebra_dual, }, + { .op = QC_UNDUAL, .process = algebra_undual, }, + + {} +}; + +static unary_type_t vector_u[] = { + { .op = '-', .result_type = &type_vector, .constant = vector_negate, }, + { .op = '!', .result_type = &type_bool, .constant = vector_not, }, + + {} +}; + +static unary_type_t entity_u[] = { + { .op = '!', .result_type = &type_bool, }, + + {} +}; + +static unary_type_t field_u[] = { + { .op = '!', .result_type = &type_bool, }, + + {} +}; + +static unary_type_t func_u[] = { + { .op = '!', .result_type = &type_bool, }, + + {} +}; + +static unary_type_t pointer_u[] = { + { .op = '!', .result_type = &type_bool, }, + { .op = '.', .process = pointer_deref, }, + + {} +}; + +static unary_type_t quat_u[] = { + { .op = '-', .result_type = &type_quaternion, .constant = quat_negate, }, + { .op = '!', .result_type = &type_bool, .constant = quat_not, }, + { .op = '~', .result_type = &type_quaternion, .constant = quat_conj, }, + + {} +}; + +static unary_type_t int_u[] = { + { .op = '-', .result_type = &type_int, .constant = int_negate, }, + { .op = '!', .result_type = &type_bool, .constant = int_not, }, + { .op = '~', .result_type = &type_int, .constant = int_bitnot, }, + { .op = QC_REVERSE, .process = algebra_reverse, }, + { .op = QC_DUAL, .process = algebra_dual, }, + { .op = QC_UNDUAL, .process = algebra_undual, }, + + {} +}; + +static unary_type_t uint_u[] = { + { .op = '-', .result_type = &type_uint, .constant = uint_negate, }, + { .op = '!', .result_type = &type_bool, .constant = uint_not, }, + { .op = '~', .result_type = &type_uint, .constant = uint_bitnot, }, + { .op = QC_REVERSE, .process = algebra_reverse, }, + { .op = QC_DUAL, .process = algebra_dual, }, + { .op = QC_UNDUAL, .process = algebra_undual, }, + + {} +}; + +static unary_type_t short_u[] = { + { .op = '-', .result_type = &type_short, .constant = short_negate, }, + { .op = '!', .result_type = &type_bool, .constant = short_not, }, + { .op = '~', .result_type = &type_short, .constant = short_bitnot, }, + { .op = QC_REVERSE, .process = algebra_reverse, }, + { .op = QC_DUAL, .process = algebra_dual, }, + { .op = QC_UNDUAL, .process = algebra_undual, }, + + {} +}; + +static unary_type_t ushort_u[] = { + { .op = '-', .result_type = &type_ushort, .constant = ushort_negate, }, + { .op = '!', .result_type = &type_bool, .constant = ushort_not, }, + { .op = '~', .result_type = &type_ushort, .constant = ushort_bitnot, }, + { .op = QC_REVERSE, .process = algebra_reverse, }, + { .op = QC_DUAL, .process = algebra_dual, }, + { .op = QC_UNDUAL, .process = algebra_undual, }, + + {} +}; + +static unary_type_t double_u[] = { + { .op = '-', .result_type = &type_double, .constant = double_negate, }, + { .op = '!', .result_type = &type_bool, .constant = double_not, }, + { .op = '~', .result_type = &type_double, .constant = double_bitnot, }, + { .op = QC_REVERSE, .process = algebra_reverse, }, + { .op = QC_DUAL, .process = algebra_dual, }, + { .op = QC_UNDUAL, .process = algebra_undual, }, + + {} +}; + +static unary_type_t long_u[] = { + { .op = '-', .result_type = &type_long, .constant = ulong_negate, }, + { .op = '!', .result_type = &type_bool, .constant = ulong_not, }, + { .op = '~', .result_type = &type_long, .constant = ulong_bitnot, }, + { .op = QC_REVERSE, .process = algebra_reverse, }, + { .op = QC_DUAL, .process = algebra_dual, }, + { .op = QC_UNDUAL, .process = algebra_undual, }, + + {} +}; + +static unary_type_t ulong_u[] = { + { .op = '-', .result_type = &type_ulong, .constant = long_negate, }, + { .op = '!', .result_type = &type_bool, .constant = long_not, }, + { .op = '~', .result_type = &type_ulong, .constant = long_bitnot, }, + { .op = QC_REVERSE, .process = algebra_reverse, }, + { .op = QC_DUAL, .process = algebra_dual, }, + { .op = QC_UNDUAL, .process = algebra_undual, }, + + {} +}; + +static unary_type_t algebra_u[] = { + { .op = '-', .process = algebra_negate, }, + { .op = '!', .process = algebra_dual, }, + { .op = '~', .process = algebra_reverse, }, + { .op = QC_REVERSE, .process = algebra_reverse, }, + { .op = QC_DUAL, .process = algebra_dual, }, + { .op = QC_UNDUAL, .process = algebra_undual, }, + + {} +}; + +static unary_type_t *unary_expr_types[ev_type_count] = { + [ev_string] = string_u, + [ev_float] = float_u, + [ev_vector] = vector_u, + [ev_entity] = entity_u, + [ev_field] = field_u, + [ev_func] = func_u, + [ev_ptr] = pointer_u, + [ev_quaternion] = quat_u, + [ev_int] = int_u, + [ev_uint] = uint_u, + [ev_short] = short_u, + [ev_ushort] = ushort_u, + [ev_double] = double_u, + [ev_long] = long_u, + [ev_ulong] = ulong_u, +}; + const expr_t * unary_expr (int op, const expr_t *e) { - vec3_t v; - quat_t q; - const char *s; - const type_t *t; - e = convert_name (e); - if (e->type == ex_error) + if (e->type == ex_error) { return e; - switch (op) { - case '-': - if (!is_math (get_type (e))) - return error (e, "invalid type for unary -"); - if (is_algebra (get_type (e))) { - return algebra_negate (e); - } - if (is_constant (e)) { - switch (extract_type (e)) { - case ev_string: - case ev_entity: - case ev_field: - case ev_func: - case ev_ptr: - internal_error (e, "type check failed!"); - case ev_double: - return new_double_expr (-expr_double (e), e->implicit); - case ev_float: - return new_float_expr (-expr_float (e), e->implicit); - case ev_vector: - VectorNegate (expr_vector (e), v); - return new_vector_expr (v); - case ev_quaternion: - QuatNegate (expr_vector (e), q); - return new_vector_expr (q); - case ev_long: - case ev_ulong: - case ev_ushort: - internal_error (e, "long not implemented"); - case ev_int: - return new_int_expr (-expr_int (e), false); - case ev_uint: - return new_uint_expr (-expr_uint (e)); - case ev_short: - return new_short_expr (-expr_short (e)); - case ev_invalid: - case ev_type_count: - case ev_void: - break; - } - internal_error (e, "weird expression type"); - } - switch (e->type) { - case ex_value: // should be handled above - case ex_error: - case ex_label: - case ex_labelref: - case ex_state: - case ex_compound: - case ex_memset: - case ex_selector: - case ex_return: - case ex_adjstk: - case ex_with: - case ex_args: - case ex_list: - case ex_type: - internal_error (e, "unexpected expression type"); - case ex_uexpr: - if (e->expr.op == '-') { - return e->expr.e1; - } - { - expr_t *n = new_unary_expr (op, e); - - n->expr.type = get_type (e); - return edag_add_expr (n); - } - case ex_block: - if (!e->block.result) { - return error (e, "invalid type for unary -"); - } - { - expr_t *n = new_unary_expr (op, e); - - n->expr.type = get_type (e); - return edag_add_expr (n); - } - case ex_branch: - case ex_inout: - return error (e, "invalid type for unary -"); - case ex_expr: - case ex_bool: - case ex_temp: - case ex_vector: - case ex_alias: - case ex_assign: - case ex_horizontal: - case ex_swizzle: - case ex_extend: - { - expr_t *n = new_unary_expr (op, e); - - n->expr.type = get_type (e); - return edag_add_expr (n); - } - case ex_def: - { - expr_t *n = new_unary_expr (op, e); - - n->expr.type = e->def->type; - return edag_add_expr (n); - } - case ex_symbol: - { - expr_t *n = new_unary_expr (op, e); - - n->expr.type = e->symbol->type; - return edag_add_expr (n); - } - case ex_multivec: - return algebra_negate (e); - case ex_nil: - case ex_address: - return error (e, "invalid type for unary -"); - case ex_count: - internal_error (e, "invalid expression"); - } - break; - case '!': - if (is_algebra (get_type (e))) { - return algebra_dual (e); - } - if (is_constant (e)) { - switch (extract_type (e)) { - case ev_entity: - case ev_field: - case ev_func: - case ev_ptr: - internal_error (e, 0); - case ev_string: - s = expr_string (e); - return new_int_expr (!s || !s[0], false); - case ev_double: - return new_int_expr (!expr_double (e), false); - case ev_float: - return new_int_expr (!expr_float (e), false); - case ev_vector: - return new_int_expr (!VectorIsZero (expr_vector (e)), - false); - case ev_quaternion: - return new_int_expr (!QuatIsZero (expr_quaternion (e)), - false); - case ev_long: - case ev_ulong: - case ev_ushort: - internal_error (e, "long not implemented"); - case ev_int: - return new_int_expr (!expr_int (e), e->implicit); - case ev_uint: - return new_uint_expr (!expr_uint (e)); - case ev_short: - return new_short_expr (!expr_short (e)); - case ev_invalid: - case ev_type_count: - case ev_void: - break; - } - internal_error (e, "weird expression type"); - } - switch (e->type) { - case ex_value: // should be handled above - case ex_error: - case ex_label: - case ex_labelref: - case ex_state: - case ex_compound: - case ex_memset: - case ex_selector: - case ex_return: - case ex_adjstk: - case ex_with: - case ex_args: - case ex_list: - case ex_type: - internal_error (e, "unexpected expression type"); - case ex_bool: - return new_bool_expr (e->boolean.false_list, - e->boolean.true_list, e); - case ex_block: - if (!e->block.result) - return error (e, "invalid type for unary !"); - case ex_uexpr: - case ex_expr: - case ex_def: - case ex_symbol: - case ex_temp: - case ex_vector: - case ex_alias: - case ex_address: - case ex_assign: - case ex_horizontal: - case ex_swizzle: - case ex_extend: - if (options.code.progsversion == PROG_VERSION) { - return binary_expr (QC_EQ, e, new_nil_expr ()); - } else { - expr_t *n = new_unary_expr (op, e); - - if (options.code.progsversion > PROG_ID_VERSION) - n->expr.type = &type_int; - else - n->expr.type = &type_float; - return n; - } - case ex_multivec: - return algebra_dual (e); - case ex_branch: - case ex_inout: - case ex_nil: - return error (e, "invalid type for unary !"); - case ex_count: - internal_error (e, "invalid expression"); - } - break; - case '~': - if (is_algebra (get_type (e))) { - return algebra_reverse (e); - } - if (is_constant (e)) { - switch (extract_type (e)) { - case ev_string: - case ev_entity: - case ev_field: - case ev_func: - case ev_ptr: - case ev_vector: - case ev_double: - return error (e, "invalid type for unary ~"); - case ev_float: - return new_float_expr (~(int) expr_float (e), - e->implicit); - case ev_quaternion: - QuatConj (expr_vector (e), q); - return new_vector_expr (q); - case ev_long: - case ev_ulong: - case ev_ushort: - internal_error (e, "long not implemented"); - case ev_int: - return new_int_expr (~expr_int (e), e->implicit); - case ev_uint: - return new_uint_expr (~expr_uint (e)); - case ev_short: - return new_short_expr (~expr_short (e)); - case ev_invalid: - t = get_type (e); - if (t->meta == ty_enum) { - return new_int_expr (~expr_int (e), false); - } - break; - case ev_type_count: - case ev_void: - break; - } - internal_error (e, "weird expression type"); - } - switch (e->type) { - case ex_value: // should be handled above - case ex_error: - case ex_label: - case ex_labelref: - case ex_state: - case ex_compound: - case ex_memset: - case ex_selector: - case ex_return: - case ex_adjstk: - case ex_with: - case ex_args: - case ex_list: - case ex_type: - internal_error (e, "unexpected expression type"); - case ex_uexpr: - if (e->expr.op == '~') - return e->expr.e1; - goto bitnot_expr; - case ex_block: - if (!e->block.result) - return error (e, "invalid type for unary ~"); - goto bitnot_expr; - case ex_branch: - case ex_inout: - return error (e, "invalid type for unary ~"); - case ex_expr: - case ex_bool: - case ex_def: - case ex_symbol: - case ex_temp: - case ex_vector: - case ex_alias: - case ex_assign: - case ex_horizontal: - case ex_swizzle: - case ex_extend: -bitnot_expr: - if (options.code.progsversion == PROG_ID_VERSION) { - const expr_t *n1 = new_int_expr (-1, false); - return binary_expr ('-', n1, e); - } else { - expr_t *n = new_unary_expr (op, e); - auto t = get_type (e); - - if (!is_integral(t) && !is_float(t) - && !is_quaternion(t)) - return error (e, "invalid type for unary ~"); - n->expr.type = t; - return n; - } - case ex_multivec: - return algebra_reverse (e); - case ex_nil: - case ex_address: - return error (e, "invalid type for unary ~"); - case ex_count: - internal_error (e, "invalid expression"); - } - break; - case '.': - { - if (extract_type (e) != ev_ptr) - return error (e, "invalid type for unary ."); - scoped_src_loc (e); - auto new = new_unary_expr ('.', e); - new->expr.type = get_type (e)->fldptr.type; - return new; - } - case '+': - if (!is_math (get_type (e))) - return error (e, "invalid type for unary +"); - return e; - case QC_REVERSE: - return algebra_reverse (e); - case QC_DUAL: - return algebra_dual (e); - case QC_UNDUAL: - return algebra_undual (e); } - internal_error (e, 0); + + unary_type_t *unary_type = nullptr; + auto t = get_type (e); + + if (op == '!' && e->type == ex_bool) { + return new_bool_expr (e->boolean.false_list, e->boolean.true_list, e); + } + + if (op == '+' && is_math (t)) { + // unary + is a no-op + return e; + } + if (is_algebra (t)) { + unary_type = algebra_u; + } else if (is_enum (t)) { + unary_type = int_u; + } else if (t->meta == ty_basic || is_handle (t)) { + unary_type = unary_expr_types[t->type]; + } + + if (!unary_type) { + return error (e, "invalid type for unary expression"); + } + while (unary_type->op && unary_type->op != op) { + unary_type++; + } + if (!unary_type->op) { + return error (e, "invalid type for unary %s", get_op_string (op)); + } + + if (unary_type->process) { + return unary_type->process (e); + } + if (is_constant (e) && !unary_type->constant) { + internal_error (e, "unexpected expression type"); + } + if (is_constant (e) && unary_type->constant) { + return unary_type->constant (e); + } + auto result_type = t; + if (unary_type->result_type) { + result_type = unary_type->result_type; + } + if (result_type == &type_bool) { + //FIXME support bool properly + if (is_long (t) || is_ulong (t) || is_double (t)) { + result_type = &type_long; + } else { + result_type = type_default; + } + } + auto new = new_unary_expr (op, e); + new->expr.type = result_type; + return new; } diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 1791252e1..d8cfe2068 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -1846,12 +1846,57 @@ expr_negate (sblock_t *sblock, const expr_t *e, operand_t **op) return statement_subexpr (sblock, neg, op); } +static sblock_t * +expr_uexpr_core (sblock_t *sblock, const expr_t *e, operand_t **op) +{ + auto opcode = convert_op (e->expr.op); + if (!opcode) { + internal_error (e, "ice ice baby"); + } + auto s = new_statement (st_expr, opcode, e); + sblock = statement_subexpr (sblock, e->expr.e1, &s->opa); + if (!*op) + *op = temp_operand (e->expr.type, e); + s->opc = *op; + sblock_add_statement (sblock, s); + return sblock; +} + +static sblock_t * +expr_not (sblock_t *sblock, const expr_t *e, operand_t **op) +{ + if (options.code.progsversion == PROG_VERSION) { + scoped_src_loc (e); + auto zero = new_nil_expr (); + zero->loc = e->loc; + zero = (expr_t *) convert_nil (zero, get_type (e->expr.e1)); + + auto not = new_binary_expr (QC_EQ, e->expr.e1, zero); + not->expr.type = e->expr.type; + not->loc = e->loc; + + return statement_subexpr (sblock, not, op); + } else { + return expr_uexpr_core (sblock, e, op); + } +} + +static sblock_t * +expr_bitnot (sblock_t *sblock, const expr_t *e, operand_t **op) +{ + if (options.code.progsversion == PROG_ID_VERSION) { + scoped_src_loc (e); + auto negone = new_int_expr (-1, false); + auto bitnot = binary_expr ('-', negone, e); + return statement_subexpr (sblock, bitnot, op); + } else { + return expr_uexpr_core (sblock, e, op); + } +} + static sblock_t * expr_uexpr (sblock_t *sblock, const expr_t *e, operand_t **op) { - const char *opcode; - statement_t *s; - switch (e->expr.op) { case '.': sblock = expr_deref (sblock, e, op); @@ -1860,19 +1905,20 @@ expr_uexpr (sblock_t *sblock, const expr_t *e, operand_t **op) sblock = expr_cast (sblock, e, op); break; case '-': - // progs has no neg instruction!?! + // progs has no neg instruction sblock = expr_negate (sblock, e, op); break; + case '!': + // rua progs has no not instruction + sblock = expr_not (sblock, e, op); + break; + case '~': + // v6 progs has no not instruction + sblock = expr_bitnot (sblock, e, op); + break; default: - opcode = convert_op (e->expr.op); - if (!opcode) - internal_error (e, "ice ice baby"); - s = new_statement (st_expr, opcode, e); - sblock = statement_subexpr (sblock, e->expr.e1, &s->opa); - if (!*op) - *op = temp_operand (e->expr.type, e); - s->opc = *op; - sblock_add_statement (sblock, s); + sblock = expr_uexpr_core (sblock, e, op); + break; } return sblock; } diff --git a/tools/qfcc/source/value.c b/tools/qfcc/source/value.c index 1400022aa..42e3d3ced 100644 --- a/tools/qfcc/source/value.c +++ b/tools/qfcc/source/value.c @@ -272,6 +272,16 @@ new_short_val (short short_val) return find_value (&val); } +ex_value_t * +new_ushort_val (unsigned short ushort_val) +{ + ex_value_t val; + memset (&val, 0, sizeof (val)); + set_val_type (&val, &type_ushort); + val.ushort_val = ushort_val; + return find_value (&val); +} + ex_value_t * new_nil_val (const type_t *type) {