mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
[qfcc] Split out the conversion evaluation code
This takes care of the FIXME regarding breaking it out for more general use (the time has come to redo constant folding).
This commit is contained in:
parent
b4afaab03c
commit
27ccad40c9
5 changed files with 211 additions and 119 deletions
|
@ -12,6 +12,7 @@ EXTRA_DIST += \
|
|||
tools/qfcc/include/emit.h \
|
||||
tools/qfcc/include/expr.h \
|
||||
tools/qfcc/include/expr_names.h \
|
||||
tools/qfcc/include/evaluate.h \
|
||||
tools/qfcc/include/flow.h \
|
||||
tools/qfcc/include/function.h \
|
||||
tools/qfcc/include/grab.h \
|
||||
|
|
47
tools/qfcc/include/evaluate.h
Normal file
47
tools/qfcc/include/evaluate.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
evaluate.h
|
||||
|
||||
constant evaluation
|
||||
|
||||
Copyright (C) 2022 Bill Currie <bill@taniwha.org>
|
||||
|
||||
Author: Bill Currie <bill@taniwha.org>
|
||||
Date: 2022/11/16
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
|
||||
Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __evaluate_h
|
||||
#define __evaluate_h
|
||||
|
||||
/** \defgroup qfcc_evaluate Constant evaluation.
|
||||
\ingroup qfcc_expr
|
||||
*/
|
||||
///@{
|
||||
|
||||
struct type_s;
|
||||
struct ex_value_s;
|
||||
struct ex_value_s *convert_value (struct ex_value_s *value,
|
||||
struct type_s *type);
|
||||
void setup_value_progs (void);
|
||||
|
||||
///@}
|
||||
|
||||
#endif//__evaluate_h
|
|
@ -32,6 +32,7 @@ qfcc_SOURCES = \
|
|||
tools/qfcc/source/expr_compound.c \
|
||||
tools/qfcc/source/expr_obj.c \
|
||||
tools/qfcc/source/expr_vector.c \
|
||||
tools/qfcc/source/evaluate.c \
|
||||
tools/qfcc/source/flow.c \
|
||||
tools/qfcc/source/function.c \
|
||||
tools/qfcc/source/grab.c \
|
||||
|
|
158
tools/qfcc/source/evaluate.c
Normal file
158
tools/qfcc/source/evaluate.c
Normal file
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
evaluate.c
|
||||
|
||||
constant evaluation
|
||||
|
||||
Copyright (C) 2022 Bill Currie <bill@taniwha.org>
|
||||
|
||||
Author: Bill Currie <bill@taniwha.org>
|
||||
Date: 2022/11/16
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
|
||||
Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA
|
||||
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//#include "QF/alloc.h"
|
||||
//#include "QF/dstring.h"
|
||||
//#include "QF/hash.h"
|
||||
//#include "QF/mathlib.h"
|
||||
#include "QF/progs.h"
|
||||
|
||||
#include "QF/simd/types.h"
|
||||
|
||||
#include "tools/qfcc/include/evaluate.h"
|
||||
#include "tools/qfcc/include/diagnostic.h"
|
||||
#include "tools/qfcc/include/expr.h"
|
||||
#include "tools/qfcc/include/options.h"
|
||||
#include "tools/qfcc/include/type.h"
|
||||
#include "tools/qfcc/include/value.h"
|
||||
|
||||
//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;
|
||||
dstatement_t *st = 0;
|
||||
switch (event) {
|
||||
case prd_trace:
|
||||
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),
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
setup_value_progs (void)
|
||||
{
|
||||
PR_Init (&value_pr);
|
||||
PR_Debug_Init (&value_pr);
|
||||
}
|
||||
|
||||
ex_value_t *
|
||||
convert_value (ex_value_t *value, type_t *type)
|
||||
{
|
||||
if (!is_math (type) || !is_math (value->type)) {
|
||||
error (0, "unable to convert non-math value");
|
||||
return value;
|
||||
}
|
||||
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 = type_size (type) - 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);
|
||||
}
|
|
@ -31,31 +31,24 @@
|
|||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "QF/alloc.h"
|
||||
#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"
|
||||
|
||||
#include "tools/qfcc/include/qfcc.h"
|
||||
#include "tools/qfcc/include/def.h"
|
||||
#include "tools/qfcc/include/defspace.h"
|
||||
#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/evaluate.h"
|
||||
#include "tools/qfcc/include/reloc.h"
|
||||
#include "tools/qfcc/include/qfcc.h"
|
||||
#include "tools/qfcc/include/strpool.h"
|
||||
#include "tools/qfcc/include/symtab.h"
|
||||
#include "tools/qfcc/include/type.h"
|
||||
|
@ -82,89 +75,6 @@ typedef struct {
|
|||
static hashtab_t *value_table;
|
||||
ALLOC_STATE (ex_value_t, values);
|
||||
|
||||
//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;
|
||||
dstatement_t *st = 0;
|
||||
switch (event) {
|
||||
case prd_trace:
|
||||
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)
|
||||
{
|
||||
|
@ -621,31 +531,6 @@ ReuseString (const char *str)
|
|||
return strpool_addstr (pr.strings, str);
|
||||
}
|
||||
|
||||
ex_value_t *
|
||||
convert_value (ex_value_t *value, type_t *type)
|
||||
{
|
||||
if (!is_math (type) || !is_math (value->type)) {
|
||||
error (0, "unable to convert non-math value");
|
||||
return value;
|
||||
}
|
||||
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 = type_size (type) - 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 *
|
||||
alias_value (ex_value_t *value, type_t *type)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue