mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 23:32:09 +00:00
Break out the defspace code.
This also makes some improvements to the free block handling code.
This commit is contained in:
parent
d3a98af783
commit
85de101aa3
4 changed files with 241 additions and 126 deletions
|
@ -75,15 +75,6 @@ typedef struct def_s {
|
|||
void *return_addr; ///< who allocated this
|
||||
} def_t;
|
||||
|
||||
typedef struct defspace_s {
|
||||
struct defspace_s *next;
|
||||
struct locref_s *free_locs;
|
||||
pr_type_t *data;
|
||||
int size;
|
||||
int max_size;
|
||||
int (*grow) (struct defspace_s *space);
|
||||
} defspace_t;
|
||||
|
||||
typedef enum {
|
||||
sc_global,
|
||||
sc_params,
|
||||
|
@ -93,7 +84,7 @@ typedef enum {
|
|||
typedef struct scope_s {
|
||||
struct scope_s *next;
|
||||
scope_type type;
|
||||
defspace_t *space;
|
||||
struct defspace_s *space;
|
||||
def_t *head;
|
||||
def_t **tail;
|
||||
int num_defs;
|
||||
|
@ -113,17 +104,13 @@ extern def_t def_void;
|
|||
extern def_t def_invalid;
|
||||
extern def_t def_function;
|
||||
|
||||
scope_t *new_scope (scope_type type, defspace_t *space, scope_t *parent);
|
||||
defspace_t *new_defspace (void);
|
||||
void defspace_adddata (defspace_t *space, pr_type_t *data, int size);
|
||||
scope_t *new_scope (scope_type type, struct defspace_s *space, scope_t *parent);
|
||||
|
||||
def_t *field_def (const char *name);
|
||||
def_t *get_def (struct type_s *type, const char *name, scope_t *scope,
|
||||
storage_class_t storage);
|
||||
def_t *new_def (struct type_s *type, const char *name, scope_t *scope);
|
||||
void set_storage_bits (def_t *def, storage_class_t storage);
|
||||
int new_location_size (int size, defspace_t *space);
|
||||
int new_location (struct type_s *type, defspace_t *space);
|
||||
void free_location (def_t *def);
|
||||
def_t *get_tempdef (struct type_s *type, scope_t *scope);
|
||||
void free_tempdefs (void);
|
||||
|
|
52
tools/qfcc/include/defspace.h
Normal file
52
tools/qfcc/include/defspace.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
defspace.h
|
||||
|
||||
management of data segments
|
||||
|
||||
Copyright (C) 2011 Bill Currie <bill@taniwha.org>
|
||||
|
||||
Author: Bill Currie <bill@taniwha.org>
|
||||
Date: 2011/01/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
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#ifndef __defspace_h
|
||||
#define __defspace_h
|
||||
|
||||
#include "QF/pr_comp.h"
|
||||
#include "QF/pr_debug.h"
|
||||
|
||||
typedef struct defspace_s {
|
||||
struct defspace_s *next;
|
||||
struct locref_s *free_locs;
|
||||
pr_type_t *data;
|
||||
int size;
|
||||
int max_size;
|
||||
int (*grow) (struct defspace_s *space);
|
||||
} defspace_t;
|
||||
|
||||
defspace_t *new_defspace (void);
|
||||
int defspace_new_loc (defspace_t *space, int size);
|
||||
void defsapce_free_loc (defspace_t *space, int ofs, int size);
|
||||
int defspace_add_data (defspace_t *space, pr_type_t *data, int size);
|
||||
|
||||
#endif//__defspace_h
|
|
@ -49,6 +49,7 @@ static __attribute__ ((used)) const char rcsid[] =
|
|||
|
||||
#include "qfcc.h"
|
||||
#include "def.h"
|
||||
#include "defspace.h"
|
||||
#include "expr.h"
|
||||
#include "immediate.h"
|
||||
#include "options.h"
|
||||
|
@ -57,12 +58,6 @@ static __attribute__ ((used)) const char rcsid[] =
|
|||
#include "struct.h"
|
||||
#include "type.h"
|
||||
|
||||
typedef struct locref_s {
|
||||
struct locref_s *next;
|
||||
int ofs;
|
||||
int size;
|
||||
} locref_t;
|
||||
|
||||
def_t def_void = { &type_void, "def void" };
|
||||
def_t def_invalid = { &type_invalid, "def invalid" };
|
||||
def_t def_function = { &type_function, "def function" };
|
||||
|
@ -71,9 +66,7 @@ static def_t *free_temps[4]; // indexted by type size
|
|||
static int tempdef_counter;
|
||||
static def_t temp_scope;
|
||||
static def_t *free_defs;
|
||||
static defspace_t *free_spaces;
|
||||
static scope_t *free_scopes;
|
||||
static locref_t *free_free_locs;
|
||||
|
||||
static hashtab_t *defs_by_name;
|
||||
static hashtab_t *field_defs;
|
||||
|
@ -97,10 +90,6 @@ check_for_name (type_t *type, const char *name, scope_t *scope,
|
|||
}
|
||||
if (!name)
|
||||
return 0;
|
||||
if (scope->type == sc_global && get_enum (name)) {
|
||||
error (0, "%s redeclared", name);
|
||||
return 0;
|
||||
}
|
||||
// see if the name is already in use
|
||||
def = (def_t *) Hash_Find (defs_by_name, name);
|
||||
if (def) {
|
||||
|
@ -118,36 +107,6 @@ check_for_name (type_t *type, const char *name, scope_t *scope,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
grow_space (defspace_t *space)
|
||||
{
|
||||
space->max_size += 1024;
|
||||
return 1;
|
||||
}
|
||||
|
||||
defspace_t *
|
||||
new_defspace (void)
|
||||
{
|
||||
defspace_t *space;
|
||||
|
||||
ALLOC (1024, defspace_t, spaces, space);
|
||||
space->grow = grow_space;
|
||||
return space;
|
||||
}
|
||||
|
||||
void
|
||||
defspace_adddata (defspace_t *space, pr_type_t *data, int size)
|
||||
{
|
||||
if (space->size + size > space->max_size) {
|
||||
space->max_size = (space->size + size + 1023) & ~1023;
|
||||
space->data = realloc (space->data,
|
||||
space->max_size * sizeof (pr_type_t));
|
||||
}
|
||||
if (data)
|
||||
memcpy (space->data + space->size, data, size * sizeof (pr_type_t));
|
||||
space->size += size;
|
||||
}
|
||||
|
||||
scope_t *
|
||||
new_scope (scope_type type, defspace_t *space, scope_t *parent)
|
||||
{
|
||||
|
@ -282,9 +241,10 @@ get_def (type_t *type, const char *name, scope_t *scope,
|
|||
def->space = space;
|
||||
if (space) {
|
||||
if (type->type == ev_field && type->t.fldptr.type == &type_vector)
|
||||
def->ofs = new_location (type->t.fldptr.type, space);
|
||||
def->ofs = defspace_new_loc (space,
|
||||
type_size (type->t.fldptr.type));
|
||||
else
|
||||
def->ofs = new_location (type, space);
|
||||
def->ofs = defspace_new_loc (space, type_size (type));
|
||||
}
|
||||
|
||||
set_storage_bits (def, storage);
|
||||
|
@ -300,8 +260,8 @@ get_def (type_t *type, const char *name, scope_t *scope,
|
|||
|
||||
if (type->type == ev_field) {
|
||||
if (storage == st_global || storage == st_static) {
|
||||
G_INT (def->ofs) = new_location (type->t.fldptr.type,
|
||||
pr.entity_data);
|
||||
G_INT (def->ofs) = defspace_new_loc (pr.entity_data,
|
||||
type_size (type->t.fldptr.type));
|
||||
reloc_def_field (def, def->ofs);
|
||||
def->constant = 1;
|
||||
def->nosave = 1;
|
||||
|
@ -348,70 +308,6 @@ new_def (type_t *type, const char *name, scope_t *scope)
|
|||
return def;
|
||||
}
|
||||
|
||||
int
|
||||
new_location_size (int size, defspace_t *space)
|
||||
{
|
||||
int ofs;
|
||||
locref_t *loc;
|
||||
locref_t **l = &space->free_locs;
|
||||
|
||||
while (*l && (*l)->size < size)
|
||||
l = &(*l)->next;
|
||||
if ((loc = *l)) {
|
||||
ofs = loc->ofs;
|
||||
if (loc->size == size) {
|
||||
*l = loc->next;
|
||||
} else {
|
||||
loc->ofs += size;
|
||||
loc->size -= size;
|
||||
}
|
||||
return ofs;
|
||||
}
|
||||
ofs = space->size;
|
||||
space->size += size;
|
||||
if (space->size > space->max_size) {
|
||||
if (!space->grow) {
|
||||
error (0, "unable to allocate %d globals", size);
|
||||
exit (1);
|
||||
}
|
||||
space->grow (space);
|
||||
}
|
||||
return ofs;
|
||||
}
|
||||
|
||||
int
|
||||
new_location (type_t *type, defspace_t *space)
|
||||
{
|
||||
return new_location_size (type_size (type), space);
|
||||
}
|
||||
|
||||
void
|
||||
free_location (def_t *def)
|
||||
{
|
||||
int size = type_size (def->type);
|
||||
locref_t *loc;
|
||||
|
||||
for (loc = def->space->free_locs; loc; loc = loc->next) {
|
||||
if (def->ofs + size == loc->ofs) {
|
||||
loc->size += size;
|
||||
loc->ofs = def->ofs;
|
||||
return;
|
||||
} else if (loc->ofs + loc->size == def->ofs) {
|
||||
loc->size += size;
|
||||
if (loc->next && loc->next->ofs == loc->ofs + loc->size) {
|
||||
loc->size += loc->next->size;
|
||||
loc->next = loc->next->next;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
ALLOC (1024, locref_t, free_locs, loc);
|
||||
loc->ofs = def->ofs;
|
||||
loc->size = size;
|
||||
loc->next = def->space->free_locs;
|
||||
def->space->free_locs = loc;
|
||||
}
|
||||
|
||||
def_t *
|
||||
get_tempdef (type_t *type, scope_t *scope)
|
||||
{
|
||||
|
@ -424,7 +320,7 @@ get_tempdef (type_t *type, scope_t *scope)
|
|||
def->type = type;
|
||||
} else {
|
||||
def = new_def (type, va (".tmp%d", tempdef_counter++), scope);
|
||||
def->ofs = new_location (type, scope->space);
|
||||
def->ofs = defspace_new_loc (scope->space, type_size (type));
|
||||
}
|
||||
def->return_addr = __builtin_return_address (0);
|
||||
def->freed = def->removed = def->users = 0;
|
||||
|
|
180
tools/qfcc/source/defspace.c
Normal file
180
tools/qfcc/source/defspace.c
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
defspace.c
|
||||
|
||||
management of data segments
|
||||
|
||||
Copyright (C) 2011 Bill Currie <bill@taniwha.org>
|
||||
|
||||
Author: Bill Currie <bill@taniwha.org>
|
||||
Date: 2011/01/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
|
||||
|
||||
static __attribute__ ((used)) const char rcsid[] = "$Id$";
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <QF/hash.h>
|
||||
#include <QF/sys.h>
|
||||
#include <QF/va.h>
|
||||
|
||||
#include "qfcc.h"
|
||||
#include "defspace.h"
|
||||
#include "expr.h"
|
||||
#include "immediate.h"
|
||||
#include "options.h"
|
||||
#include "reloc.h"
|
||||
#include "strpool.h"
|
||||
#include "struct.h"
|
||||
#include "type.h"
|
||||
|
||||
typedef struct locref_s {
|
||||
struct locref_s *next;
|
||||
int ofs;
|
||||
int size;
|
||||
} locref_t;
|
||||
|
||||
static defspace_t *free_spaces;
|
||||
static locref_t *free_locrefs;
|
||||
|
||||
static int
|
||||
grow_space (defspace_t *space)
|
||||
{
|
||||
space->max_size += 1024;
|
||||
return 1;
|
||||
}
|
||||
|
||||
defspace_t *
|
||||
new_defspace (void)
|
||||
{
|
||||
defspace_t *space;
|
||||
|
||||
ALLOC (1024, defspace_t, spaces, space);
|
||||
space->grow = grow_space;
|
||||
return space;
|
||||
}
|
||||
|
||||
int
|
||||
defspace_new_loc (defspace_t *space, int size)
|
||||
{
|
||||
int ofs;
|
||||
locref_t *loc;
|
||||
locref_t **l = &space->free_locs;
|
||||
|
||||
while (*l && (*l)->size < size)
|
||||
l = &(*l)->next;
|
||||
if ((loc = *l)) {
|
||||
ofs = (*l)->ofs;
|
||||
if ((*l)->size == size) {
|
||||
loc = *l;
|
||||
*l = (*l)->next;
|
||||
loc->next = free_locrefs;
|
||||
free_locrefs = loc;
|
||||
} else {
|
||||
(*l)->ofs += size;
|
||||
(*l)->size -= size;
|
||||
}
|
||||
return ofs;
|
||||
}
|
||||
ofs = space->size;
|
||||
space->size += size;
|
||||
if (space->size > space->max_size) {
|
||||
if (!space->grow) {
|
||||
error (0, "unable to allocate %d globals", size);
|
||||
exit (1);
|
||||
}
|
||||
space->grow (space);
|
||||
}
|
||||
return ofs;
|
||||
}
|
||||
|
||||
void
|
||||
defsapce_free_loc (defspace_t *space, int ofs, int size)
|
||||
{
|
||||
locref_t **l;
|
||||
locref_t *loc;
|
||||
|
||||
if (!size)
|
||||
internal_error (0, "defspace: freeing size 0 location");
|
||||
if (ofs < 0 || ofs >= space->size || ofs + size > space->size)
|
||||
internal_error (0, "defspace: freeing bogus location %d:%d",
|
||||
ofs, size);
|
||||
for (l = &space->free_locs; l; l = &(*l)->next) {
|
||||
loc = *l;
|
||||
// location to be freed is below the free block
|
||||
// need to create a new free block
|
||||
if (ofs + size < loc->ofs)
|
||||
break;
|
||||
// location to be freed is immediately below the free block
|
||||
// merge with the free block
|
||||
if (ofs + size == loc->ofs) {
|
||||
loc->size += size;
|
||||
loc->ofs = ofs;
|
||||
return;
|
||||
}
|
||||
// location to be freed overlaps the free block
|
||||
// this is an error
|
||||
if (ofs + size > loc->ofs && ofs < loc->ofs + loc->size)
|
||||
internal_error (0, "defspace: freeing bogus location %d:%d",
|
||||
ofs, size);
|
||||
// location to be freed is immediately above the free block
|
||||
// merge with the free block
|
||||
if (ofs == loc->ofs + loc->size) {
|
||||
loc->size += size;
|
||||
// location to be freed is immediately below the next free block
|
||||
// merge with the next block too, and unlink that block
|
||||
if (loc->next && loc->next->ofs == loc->ofs + loc->size) {
|
||||
loc->size += loc->next->size;
|
||||
loc = loc->next;
|
||||
*l = loc->next;
|
||||
loc->next = free_locrefs;
|
||||
free_locrefs = loc;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
// insert a new free block for the location to be freed
|
||||
ALLOC (1024, locref_t, locrefs, loc);
|
||||
loc->ofs = ofs;
|
||||
loc->size = size;
|
||||
loc->next = *l;
|
||||
*l = loc;
|
||||
}
|
||||
|
||||
int
|
||||
defspace_add_data (defspace_t *space, pr_type_t *data, int size)
|
||||
{
|
||||
int loc;
|
||||
|
||||
loc = defspace_new_loc (space, size);
|
||||
if (data)
|
||||
memcpy (space->data + loc, data, size * sizeof (pr_type_t));
|
||||
return loc;
|
||||
}
|
Loading…
Reference in a new issue