mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-18 23:11:38 +00:00
[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:
parent
e1d7854af5
commit
23469029ca
2 changed files with 104 additions and 83 deletions
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue