2001-04-01 02:12:57 +00:00
|
|
|
/* Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
|
|
|
|
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 the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
|
|
|
See file, 'COPYING', for details.
|
|
|
|
*/
|
2001-09-28 07:09:38 +00:00
|
|
|
static const char rcsid[] =
|
|
|
|
"$Id$";
|
2001-04-01 02:12:57 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
#include <QF/hash.h>
|
2001-10-24 22:50:06 +00:00
|
|
|
#include <QF/sys.h>
|
2001-04-01 02:12:57 +00:00
|
|
|
|
|
|
|
#include "qfcc.h"
|
|
|
|
|
2001-06-08 06:32:15 +00:00
|
|
|
typedef struct locref_s {
|
|
|
|
struct locref_s *next;
|
|
|
|
int ofs;
|
|
|
|
} locref_t;
|
2001-04-01 02:12:57 +00:00
|
|
|
|
|
|
|
def_t *pr_global_defs[MAX_REGS]; // to find def for a global variable
|
2001-06-05 05:22:11 +00:00
|
|
|
static def_t *free_temps[4]; // indexted by type size
|
2001-06-04 17:52:50 +00:00
|
|
|
static def_t temp_scope;
|
2001-06-08 06:32:15 +00:00
|
|
|
static locref_t *free_locs[4]; // indexted by type size
|
|
|
|
static locref_t *free_free_locs;
|
2001-04-01 02:12:57 +00:00
|
|
|
|
2001-04-01 06:01:02 +00:00
|
|
|
static hashtab_t *defs_by_name;
|
2001-04-01 02:12:57 +00:00
|
|
|
|
2001-06-04 04:52:14 +00:00
|
|
|
static const char *
|
2001-04-01 02:12:57 +00:00
|
|
|
defs_get_key (void *_def, void *_tab)
|
|
|
|
{
|
|
|
|
def_t *def = (def_t*)_def;
|
|
|
|
hashtab_t **tab = (hashtab_t**) _tab;
|
|
|
|
|
|
|
|
if (tab == &defs_by_name) {
|
|
|
|
return def->name;
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2001-11-13 08:58:54 +00:00
|
|
|
static def_t *
|
|
|
|
check_for_name (type_t *type, const char *name, def_t *scope, int *allocate)
|
2001-04-01 02:12:57 +00:00
|
|
|
{
|
|
|
|
def_t *def;
|
|
|
|
|
|
|
|
if (!defs_by_name) {
|
2001-04-01 06:40:51 +00:00
|
|
|
defs_by_name = Hash_NewTable (16381, defs_get_key, 0, &defs_by_name);
|
2001-04-01 02:12:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// see if the name is already in use
|
|
|
|
def = (def_t*) Hash_Find (defs_by_name, name);
|
|
|
|
if (def) {
|
|
|
|
if (allocate && scope == def->scope)
|
|
|
|
if (type && def->type != type)
|
2001-08-10 18:35:55 +00:00
|
|
|
error (0, "Type mismatch on redeclaration of %s", name);
|
2001-04-01 02:12:57 +00:00
|
|
|
if (!allocate || def->scope == scope)
|
|
|
|
return def;
|
|
|
|
}
|
2001-11-13 08:58:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline type_t *
|
|
|
|
find_type (type_t *type, type_t *aux_type)
|
|
|
|
{
|
|
|
|
type_t new;
|
|
|
|
memset (&new, 0, sizeof (new));
|
|
|
|
new.type = type->type;
|
|
|
|
new.aux_type = aux_type;
|
2001-11-15 00:46:36 +00:00
|
|
|
new.num_parms = 0;
|
2001-11-13 08:58:54 +00:00
|
|
|
return PR_FindType (&new);
|
|
|
|
}
|
|
|
|
|
|
|
|
def_t *
|
|
|
|
PR_GetArray (type_t *etype, const char *name, int size, def_t *scope,
|
|
|
|
int *allocate)
|
|
|
|
{
|
|
|
|
type_t *type = find_type (&type_pointer, etype);
|
|
|
|
def_t *def = check_for_name (type, name, scope, allocate);
|
|
|
|
if (def || !allocate)
|
|
|
|
return def;
|
|
|
|
def = PR_NewDef (type, name, scope);
|
|
|
|
def->ofs = *allocate;
|
2001-11-13 18:11:19 +00:00
|
|
|
def->initialized = def->constant = 1;
|
2001-11-13 08:58:54 +00:00
|
|
|
*allocate += pr_type_size [type->type] * size + 1;
|
|
|
|
pr_global_defs[def->ofs] = def;
|
|
|
|
G_INT (def->ofs) = def->ofs + 1;
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
PR_GetDef
|
|
|
|
|
|
|
|
If type is NULL, it will match any type
|
|
|
|
If allocate is true, a new def will be allocated if it can't be found
|
|
|
|
*/
|
|
|
|
def_t *
|
|
|
|
PR_GetDef (type_t *type, const char *name, def_t *scope, int *allocate)
|
|
|
|
{
|
|
|
|
def_t *def = check_for_name (type, name, scope, allocate);
|
|
|
|
char element[MAX_NAME];
|
2001-04-01 02:12:57 +00:00
|
|
|
|
2001-11-13 08:58:54 +00:00
|
|
|
if (def || !allocate)
|
|
|
|
return def;
|
2001-04-01 02:12:57 +00:00
|
|
|
|
|
|
|
// allocate a new def
|
|
|
|
def = PR_NewDef (type, name, scope);
|
|
|
|
Hash_Add (defs_by_name, def);
|
|
|
|
|
2001-06-08 06:32:15 +00:00
|
|
|
//FIXME: need to sort out location re-use
|
2001-06-05 08:09:12 +00:00
|
|
|
def->ofs = *allocate;
|
|
|
|
pr_global_defs[*allocate] = def;
|
2001-04-01 02:12:57 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
make automatic defs for the vectors elements
|
|
|
|
.origin can be accessed as .origin_x, .origin_y, and .origin_z
|
|
|
|
*/
|
|
|
|
if (type->type == ev_vector) {
|
2001-09-22 23:41:47 +00:00
|
|
|
def_t *d;
|
|
|
|
|
2001-04-01 02:12:57 +00:00
|
|
|
sprintf (element, "%s_x", name);
|
2001-09-22 23:41:47 +00:00
|
|
|
d = PR_GetDef (&type_float, element, scope, allocate);
|
|
|
|
d->used = 1;
|
2001-10-18 20:05:26 +00:00
|
|
|
d->parent = def;
|
2001-04-01 02:12:57 +00:00
|
|
|
|
|
|
|
sprintf (element, "%s_y", name);
|
2001-09-22 23:41:47 +00:00
|
|
|
d = PR_GetDef (&type_float, element, scope, allocate);
|
|
|
|
d->used = 1;
|
2001-10-18 20:05:26 +00:00
|
|
|
d->parent = def;
|
2001-04-01 02:12:57 +00:00
|
|
|
|
|
|
|
sprintf (element, "%s_z", name);
|
2001-09-22 23:41:47 +00:00
|
|
|
d = PR_GetDef (&type_float, element, scope, allocate);
|
|
|
|
d->used = 1;
|
2001-10-18 20:05:26 +00:00
|
|
|
d->parent = def;
|
2001-04-01 02:12:57 +00:00
|
|
|
} else {
|
2001-11-12 23:56:46 +00:00
|
|
|
*allocate += pr_type_size[type->type];
|
2001-04-01 02:12:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (type->type == ev_field) {
|
|
|
|
*(int *) &pr_globals[def->ofs] = pr.size_fields;
|
|
|
|
|
|
|
|
if (type->aux_type->type == ev_vector) {
|
2001-09-22 23:41:47 +00:00
|
|
|
def_t *d;
|
|
|
|
|
2001-04-01 02:12:57 +00:00
|
|
|
sprintf (element, "%s_x", name);
|
2001-09-22 23:41:47 +00:00
|
|
|
d = PR_GetDef (&type_floatfield, element, scope, allocate);
|
|
|
|
d->used = 1; // always `used'
|
2001-10-18 20:05:26 +00:00
|
|
|
d->parent = def;
|
2001-04-01 02:12:57 +00:00
|
|
|
|
|
|
|
sprintf (element, "%s_y", name);
|
2001-09-22 23:41:47 +00:00
|
|
|
d = PR_GetDef (&type_floatfield, element, scope, allocate);
|
|
|
|
d->used = 1; // always `used'
|
2001-10-18 20:05:26 +00:00
|
|
|
d->parent = def;
|
2001-04-01 02:12:57 +00:00
|
|
|
|
|
|
|
sprintf (element, "%s_z", name);
|
2001-09-22 23:41:47 +00:00
|
|
|
d = PR_GetDef (&type_floatfield, element, scope, allocate);
|
|
|
|
d->used = 1; // always `used'
|
2001-10-18 20:05:26 +00:00
|
|
|
d->parent = def;
|
2001-04-01 02:12:57 +00:00
|
|
|
} else {
|
2001-11-12 23:56:46 +00:00
|
|
|
pr.size_fields += pr_type_size[type->aux_type->type];
|
2001-04-01 02:12:57 +00:00
|
|
|
}
|
2001-11-15 00:46:36 +00:00
|
|
|
} else if (type->type == ev_pointer) {
|
|
|
|
*allocate += type->num_parms * pr_type_size[type->aux_type->type];
|
|
|
|
def->initialized = def->constant = 1;
|
2001-04-01 02:12:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
def_t *
|
|
|
|
PR_NewDef (type_t *type, const char *name, def_t *scope)
|
|
|
|
{
|
|
|
|
def_t *def;
|
|
|
|
|
|
|
|
def = calloc (1, sizeof (def_t));
|
2001-06-04 05:45:51 +00:00
|
|
|
|
|
|
|
if (name) {
|
2001-06-20 03:05:50 +00:00
|
|
|
pr.def_tail->def_next = def;
|
2001-06-04 05:45:51 +00:00
|
|
|
pr.def_tail = def;
|
|
|
|
}
|
2001-04-01 02:12:57 +00:00
|
|
|
|
|
|
|
if (scope) {
|
|
|
|
def->scope_next = scope->scope_next;
|
|
|
|
scope->scope_next = def;
|
|
|
|
}
|
|
|
|
|
2001-06-04 05:45:51 +00:00
|
|
|
def->name = name ? strdup (name) : 0;
|
2001-04-01 02:12:57 +00:00
|
|
|
def->type = type;
|
|
|
|
|
|
|
|
def->scope = scope;
|
|
|
|
|
2001-09-22 23:41:47 +00:00
|
|
|
def->file = s_file;
|
|
|
|
def->line = pr_source_line;
|
|
|
|
|
2001-04-01 02:12:57 +00:00
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
2001-06-08 06:32:15 +00:00
|
|
|
int
|
|
|
|
PR_NewLocation (type_t *type)
|
|
|
|
{
|
2001-11-12 23:56:46 +00:00
|
|
|
int size = pr_type_size[type->type];
|
2001-06-08 06:32:15 +00:00
|
|
|
locref_t *loc;
|
|
|
|
|
|
|
|
if (free_locs[size]) {
|
|
|
|
loc = free_locs[size];
|
|
|
|
free_locs[size] = loc->next;
|
|
|
|
|
|
|
|
loc->next = free_free_locs;
|
|
|
|
free_free_locs = loc;
|
|
|
|
|
|
|
|
return loc->ofs;
|
|
|
|
}
|
|
|
|
numpr_globals += size;
|
|
|
|
return numpr_globals - size;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
PR_FreeLocation (def_t *def)
|
|
|
|
{
|
2001-11-12 23:56:46 +00:00
|
|
|
int size = pr_type_size[def->type->type];
|
2001-06-08 06:32:15 +00:00
|
|
|
locref_t *loc;
|
|
|
|
|
|
|
|
if (!free_free_locs) {
|
|
|
|
free_free_locs = malloc (256 * sizeof (locref_t));
|
2001-10-24 22:50:06 +00:00
|
|
|
if (!free_free_locs)
|
|
|
|
Sys_Error ("PR_FreeLocation: Memory Allocation Failure\n");
|
2001-06-08 06:32:15 +00:00
|
|
|
for (loc = free_free_locs; loc - free_free_locs < 255; loc++)
|
|
|
|
loc->next = loc + 1;
|
|
|
|
loc->next = 0;
|
|
|
|
}
|
|
|
|
loc = free_free_locs;
|
|
|
|
free_free_locs = loc->next;
|
|
|
|
loc->ofs = def->ofs;
|
|
|
|
loc->next = free_locs[size];
|
|
|
|
free_locs[size] = loc;
|
|
|
|
}
|
|
|
|
|
2001-06-04 17:52:50 +00:00
|
|
|
def_t *
|
2001-06-05 05:22:11 +00:00
|
|
|
PR_GetTempDef (type_t *type, def_t *scope)
|
2001-06-04 17:52:50 +00:00
|
|
|
{
|
2001-11-12 23:56:46 +00:00
|
|
|
int size = pr_type_size[type->type];
|
2001-06-05 05:22:11 +00:00
|
|
|
def_t *def;
|
|
|
|
if (free_temps[size]) {
|
|
|
|
def = free_temps[size];
|
|
|
|
free_temps[size] = def->next;
|
|
|
|
def->type = type;
|
2001-06-04 17:52:50 +00:00
|
|
|
} else {
|
2001-06-05 05:22:11 +00:00
|
|
|
def = PR_NewDef (type, 0, scope);
|
2001-10-24 06:39:49 +00:00
|
|
|
def->ofs = *scope->alloc;
|
2001-11-12 23:56:46 +00:00
|
|
|
*scope->alloc += pr_type_size[size];
|
2001-06-04 17:52:50 +00:00
|
|
|
}
|
2001-11-13 23:21:23 +00:00
|
|
|
def->freed = def->removed = def->users = 0;
|
2001-06-05 05:22:11 +00:00
|
|
|
def->next = temp_scope.next;
|
|
|
|
temp_scope.next = def;
|
|
|
|
return def;
|
2001-06-04 17:52:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
PR_FreeTempDefs (void)
|
|
|
|
{
|
2001-08-22 21:55:01 +00:00
|
|
|
def_t **def, *d;
|
2001-06-05 05:22:11 +00:00
|
|
|
int size;
|
|
|
|
|
2001-08-22 21:55:01 +00:00
|
|
|
def = &temp_scope.next;
|
|
|
|
while (*def) {
|
|
|
|
if ((*def)->users <= 0) {
|
|
|
|
d = *def;
|
|
|
|
*def = d->next;
|
|
|
|
|
pr_comp.h:
o add ev_uniteger to the types enum
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
progs.h:
o add uinteger accessors
pr_exec.c:
o implement ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
pr_opcode.c:
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
expr.h:
o prototype inc_users
qfcc.h:
o add externs for op_ifbe, op_ifb, op_ifae and op_ifa
emit.c:
o don't bother emiting an assignment to a temp def that's only used once
(ie, it's never read, only written to)
o support the new if* instructions
expr.c:
o support the new if* insructions
o dectect expression loops in append_expr
o support unsigned integers
o re-work temp def usage counting
pr_def.c
o debugging for temp def usage counts
pr_opcode.c:
o support the new if* instructions
qc-parse.y:
o provide defines for IFBE IFB IFAE IFA
switch.c:
o do binary searches for strings, floats and ints if there are more than
8 cases in a switch. Strings need more testing.
2001-11-09 00:58:16 +00:00
|
|
|
if (d->users < 0)
|
2001-11-13 18:49:27 +00:00
|
|
|
printf ("%s:%d: warning: %s %3d %3d\n", strings + d->file, d->line, type_name[d->type->type], d->ofs, d->users);
|
2001-11-12 23:56:46 +00:00
|
|
|
size = pr_type_size[d->type->type];
|
2001-08-22 21:55:01 +00:00
|
|
|
if (d->expr)
|
|
|
|
d->expr->e.temp.def = 0;
|
|
|
|
|
2001-11-13 18:11:19 +00:00
|
|
|
if (!d->freed) {
|
|
|
|
d->next = free_temps[size];
|
|
|
|
free_temps[size] = d;
|
|
|
|
d->freed = 1;
|
|
|
|
}
|
2001-08-22 21:55:01 +00:00
|
|
|
} else {
|
|
|
|
def = &(*def)->next;
|
|
|
|
}
|
2001-06-04 17:52:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-06-04 22:35:54 +00:00
|
|
|
void
|
|
|
|
PR_ResetTempDefs (void)
|
|
|
|
{
|
|
|
|
int i;
|
2001-08-22 21:55:01 +00:00
|
|
|
def_t *d;
|
2001-06-04 22:35:54 +00:00
|
|
|
|
2001-06-05 08:09:12 +00:00
|
|
|
for (i = 0; i < sizeof (free_temps) / sizeof (free_temps[0]); i++) {
|
2001-06-05 05:22:11 +00:00
|
|
|
free_temps[i] = 0;
|
2001-06-04 22:35:54 +00:00
|
|
|
}
|
2001-08-22 21:55:01 +00:00
|
|
|
|
|
|
|
for (d = temp_scope.next; d; d = d->next)
|
2001-11-13 18:49:27 +00:00
|
|
|
printf ("%s:%d: warning: %s %3d %3d\n", strings + d->file, d->line, type_name[d->type->type], d->ofs, d->users);
|
2001-08-22 21:55:01 +00:00
|
|
|
temp_scope.next = 0;
|
2001-06-04 22:35:54 +00:00
|
|
|
}
|
|
|
|
|
2001-04-01 02:12:57 +00:00
|
|
|
void
|
2001-09-22 23:41:47 +00:00
|
|
|
PR_FlushScope (def_t *scope, int force_used)
|
2001-04-01 02:12:57 +00:00
|
|
|
{
|
|
|
|
def_t *def;
|
|
|
|
|
|
|
|
for (def = scope->scope_next; def; def = def->scope_next) {
|
2001-09-22 23:41:47 +00:00
|
|
|
if (def->name) {
|
|
|
|
if (!force_used && !def->used) {
|
|
|
|
expr_t e;
|
|
|
|
e.line = def->line;
|
|
|
|
e.file = def->file;
|
2001-09-24 17:51:15 +00:00
|
|
|
warning (&e, "unused variable `%s'", def->name);
|
2001-09-22 23:41:47 +00:00
|
|
|
}
|
2001-10-24 06:39:49 +00:00
|
|
|
if (!def->removed) {
|
|
|
|
Hash_Del (defs_by_name, def->name);
|
|
|
|
def->removed = 1;
|
|
|
|
}
|
2001-09-22 23:41:47 +00:00
|
|
|
}
|
2001-04-01 02:12:57 +00:00
|
|
|
}
|
|
|
|
}
|
2001-10-18 20:05:26 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
PR_DefInitialized (def_t *d)
|
|
|
|
{
|
|
|
|
d->initialized = 1;
|
|
|
|
if (d->type == &type_vector
|
|
|
|
|| (d->type->type == ev_field
|
|
|
|
&& d->type->aux_type == &type_vector)) {
|
|
|
|
d = d->def_next;
|
|
|
|
d->initialized = 1;
|
|
|
|
d = d->def_next;
|
|
|
|
d->initialized = 1;
|
|
|
|
d = d->def_next;
|
|
|
|
d->initialized = 1;
|
|
|
|
}
|
|
|
|
if (d->parent) {
|
|
|
|
d = d->parent;
|
|
|
|
if (d->type == &type_vector
|
|
|
|
&& d->def_next->initialized
|
|
|
|
&& d->def_next->def_next->initialized
|
|
|
|
&& d->def_next->def_next->def_next->initialized)
|
|
|
|
d->initialized = 1;
|
|
|
|
}
|
|
|
|
}
|