Break out the defspace code.

This also makes some improvements to the free block handling code.
This commit is contained in:
Bill Currie 2011-01-17 12:06:15 +09:00
parent d3a98af783
commit 85de101aa3
4 changed files with 241 additions and 126 deletions

View file

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

View 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

View file

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

View 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;
}