diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index bab482a9f..76286dce6 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -637,7 +637,7 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, warning (init, "assigning double to %s in initializer " "(use a cast)", sym->type->name); } - if (is_scalar (sym->type)) + if (!type_same (sym->type, init_type)) v = convert_value (v, sym->type); if (v->lltype == ev_string) { EMIT_STRING (sym->s.def->space, D_STRING (sym->s.def), diff --git a/tools/qfcc/source/value.c b/tools/qfcc/source/value.c index 7ea649782..58ca36a35 100644 --- a/tools/qfcc/source/value.c +++ b/tools/qfcc/source/value.c @@ -43,6 +43,7 @@ #include "QF/dstring.h" #include "QF/hash.h" #include "QF/mathlib.h" +#include "QF/progs.h" #include "QF/va.h" #include "QF/simd/types.h" @@ -53,6 +54,7 @@ #include "tools/qfcc/include/diagnostic.h" #include "tools/qfcc/include/emit.h" #include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/options.h" #include "tools/qfcc/include/reloc.h" #include "tools/qfcc/include/strpool.h" #include "tools/qfcc/include/symtab.h" @@ -80,6 +82,88 @@ typedef struct { static hashtab_t *value_table; static ex_value_t *values_freelist; +//FIXME this (to setup_value_progs) should be in its own file and more +//general (good for constant folding, too, and maybe some others). +static void +value_debug_handler (prdebug_t event, void *param, void *data) +{ + progs_t *pr = data; + switch (event) { + case prd_trace: + dstatement_t *st = pr->pr_statements + pr->pr_xstatement; + PR_PrintStatement (pr, st, 0); + break; + case prd_breakpoint: + case prd_subenter: + case prd_subexit: + case prd_runerror: + case prd_watchpoint: + case prd_begin: + case prd_terminate: + case prd_error: + case prd_none: + break; + } +} + +enum { + vf_null, + vf_convert, +}; + +#define BASE(b, base) (((base) & 3) << OP_##b##_SHIFT) +#define OP(a, b, c, op) ((op) | BASE(A, a) | BASE(B, b) | BASE(C, c)) + +static bfunction_t value_functions[] = { + {}, // null function + [vf_convert] = { .first_statement = vf_convert * 16 }, +}; + +static __attribute__((aligned(64))) +dstatement_t value_statements[] = { + [vf_convert * 16 - 1] = {}, + { OP_CONV, 0, 07777, 16 }, + { OP_RETURN, 16, 0, 0 }, +}; + +#define num_globals 16384 +#define stack_size 8192 +static __attribute__((aligned(64))) +pr_type_t value_globals[num_globals + 128] = { + [num_globals - stack_size] = { .uint_value = num_globals }, +}; + +static dprograms_t value_progs = { + .version = PROG_VERSION, + .statements = { + .count = sizeof (value_statements) / sizeof (value_statements[0]), + }, +}; +static progs_t value_pr = { + .progs = &value_progs, + .debug_handler = value_debug_handler, + .debug_data = &value_pr, + .pr_trace = 1, + .pr_trace_depth = -1, + .function_table = value_functions, + .pr_statements = value_statements, + .globals_size = num_globals, + .pr_globals = value_globals, + .stack_bottom = num_globals - stack_size + 4, + .pr_return_buffer = value_globals + num_globals, + .pr_return = value_globals + num_globals, + .globals = { + .stack = (pr_ptr_t *) (value_globals + num_globals - stack_size), + } +}; + +static void +setup_value_progs (void) +{ + PR_Init (&value_pr); + PR_Debug_Init (&value_pr); +} + static uintptr_t value_get_hash (const void *_val, void *unused) { @@ -536,94 +620,29 @@ ReuseString (const char *str) return strpool_addstr (pr.strings, str); } -static float -value_as_float (ex_value_t *value) -{ - if (value->lltype == ev_uint) - return value->v.uint_val; - if (value->lltype == ev_int) - return value->v.int_val; - if (value->lltype == ev_short) - return value->v.short_val; - if (value->lltype == ev_double) - return value->v.double_val; - if (value->lltype == ev_float) - return value->v.float_val; - return 0; -} - -static double -value_as_double (ex_value_t *value) -{ - if (value->lltype == ev_uint) - return value->v.uint_val; - if (value->lltype == ev_int) - return value->v.int_val; - if (value->lltype == ev_short) - return value->v.short_val; - if (value->lltype == ev_double) - return value->v.double_val; - if (value->lltype == ev_float) - return value->v.float_val; - return 0; -} - -static int -value_as_int (ex_value_t *value) -{ - if (value->lltype == ev_uint) - return value->v.uint_val; - if (value->lltype == ev_int) - return value->v.int_val; - if (value->lltype == ev_short) - return value->v.short_val; - if (value->lltype == ev_double) - return value->v.double_val; - if (value->lltype == ev_float) - return value->v.float_val; - return 0; -} - -static unsigned -value_as_uint (ex_value_t *value) -{ - if (value->lltype == ev_uint) - return value->v.uint_val; - if (value->lltype == ev_int) - return value->v.int_val; - if (value->lltype == ev_short) - return value->v.short_val; - if (value->lltype == ev_double) - return value->v.double_val; - if (value->lltype == ev_float) - return value->v.float_val; - return 0; -} - ex_value_t * convert_value (ex_value_t *value, type_t *type) { - if (!is_scalar (type) || !is_scalar (ev_types[value->lltype])) { - error (0, "unable to convert non-scalar value"); + if (!is_math (type) || !is_math (value->type)) { + error (0, "unable to convert non-math value"); return value; } - if (is_float (type)) { - float val = value_as_float (value); - return new_float_val (val); - } else if (is_double (type)) { - double val = value_as_double (value); - return new_double_val (val); - } else if (type->type == ev_short) { - int val = value_as_int (value); - return new_short_val (val); - } else if (type->type == ev_uint) { - unsigned val = value_as_uint (value); - return new_uint_val (val); - } else { - //FIXME handle enums separately? - int val = value_as_int (value); - return new_int_val (val); + if (type_width (type) != type_width (value->type)) { + error (0, "unable to convert between values of different widths"); + return value; } + int from = type_cast_map[base_type (value->type)->type]; + int to = type_cast_map[base_type (type)->type]; + int width = type_width (value->type) - 1; + int conv = TYPE_CAST_CODE (from, to, width); + int addr = value_functions[vf_convert].first_statement; + value_statements[addr + 0].b = conv; + value_statements[addr + 1].c = width; // width is actual width - 1 + memcpy (value_globals, &value->v, + type_size (value->type) * sizeof (pr_type_t)); + value_pr.pr_trace = options.verbosity > 1; + PR_ExecuteProgram (&value_pr, vf_convert); + return new_type_value (type, value_pr.pr_return_buffer); } ex_value_t * @@ -788,6 +807,8 @@ clear_immediates (void) Hash_FlushTable (fldptr_imm_defs); Hash_FlushTable (value_imm_defs); } else { + setup_value_progs (); + value_table = Hash_NewTable (16381, 0, 0, 0, 0); Hash_SetHashCompare (value_table, value_get_hash, value_compare);