[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.
This commit is contained in:
Bill Currie 2022-11-16 17:55:56 +09:00
parent e1d7854af5
commit 23469029ca
2 changed files with 104 additions and 83 deletions

View file

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

View file

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