From 23469029ca38d82f1a752f7582d72063fc9aecd1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 16 Nov 2022 17:55:56 +0900 Subject: [PATCH] [qfcc] Support converting non-scalar values This fixes the basic vecconst test (extending it to other types breaks because long and ulong are not properly supported yet). The conversion is done by the progs VM rather than writing another 256 conversions (though loops could be used). This works nicely as a test for using the VM to help with compiling. --- tools/qfcc/source/def.c | 2 +- tools/qfcc/source/value.c | 185 +++++++++++++++++++++----------------- 2 files changed, 104 insertions(+), 83 deletions(-) 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);