redo relocations

This commit is contained in:
Bill Currie 2002-06-07 17:29:30 +00:00
parent 442ccc3deb
commit 00a54ad918
12 changed files with 240 additions and 116 deletions

View file

@ -43,7 +43,7 @@ typedef struct def_s {
int ofs;
int initialized; // for uninit var detection
int constant; // 1 when a declaration included "= immediate"
struct statref_s *refs; // for relocations
struct reloc_s *refs; // for relocations
unsigned freed:1; // already freed from the scope
unsigned removed:1; // already removed from the symbol table

View file

@ -56,8 +56,9 @@ typedef enum {
ex_short,
} expr_type;
typedef struct {
struct statref_s *refs;
typedef struct ex_label_s {
struct ex_label_s *next;
struct reloc_s *refs;
int ofs;
const char *name;
} ex_label_t;

View file

@ -32,31 +32,23 @@
#ifndef __opcodes_h
#define __opcodes_h
#include "QF/pr_comp.h"
extern struct opcode_s *op_done;
extern struct opcode_s *op_return;
extern struct opcode_s *op_if;
extern struct opcode_s *op_ifnot;
extern struct opcode_s *op_ifbe;
extern struct opcode_s *op_ifb;
extern struct opcode_s *op_ifae;
extern struct opcode_s *op_ifa;
extern struct opcode_s *op_state;
extern struct opcode_s *op_goto;
extern struct opcode_s *op_jump;
extern struct opcode_s *op_jumpb;
typedef struct statref_s {
struct statref_s *next;
int ofs;
int field; // a, b, c (0, 1, 2)
} statref_t;
struct def_s;
extern opcode_t *op_done;
extern opcode_t *op_return;
extern opcode_t *op_if;
extern opcode_t *op_ifnot;
extern opcode_t *op_ifbe;
extern opcode_t *op_ifb;
extern opcode_t *op_ifae;
extern opcode_t *op_ifa;
extern opcode_t *op_state;
extern opcode_t *op_goto;
extern opcode_t *op_jump;
extern opcode_t *op_jumpb;
statref_t *PR_NewStatref (int ofs, int field);
void PR_AddStatementRef (struct def_s *def, dstatement_t *st, int field);
opcode_t *PR_Opcode_Find (const char *name, struct def_s *var_a,
struct def_s *var_b, struct def_s *var_c);
void PR_Opcode_Init_Tables (void);
struct opcode_s *opcode_find (const char *name, struct def_s *var_a,
struct def_s *var_b, struct def_s *var_c);
void opcode_init (void);
#endif//__opcodes_h

View file

@ -45,6 +45,7 @@
//
typedef struct {
struct type_s *types;
struct ex_label_s *labels;
struct def_s *def_head; // unused head of linked list
struct def_s **def_tail; // add new defs after this and move it

View file

@ -0,0 +1,58 @@
/*
reloc.h
#DESCRIPTION#
Copyright (C) 2001 #AUTHOR#
Author: #AUTHOR#
Date: #DATE#
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 __reloc_h
#define __reloc_h
typedef enum {
rel_none,
rel_op_a_def,
rel_op_b_def,
rel_op_c_def,
rel_op_a_op,
rel_op_b_op,
rel_op_c_op,
rel_def_op,
rel_def_def,
} reloc_type;
typedef struct reloc_s {
struct reloc_s *next;
int ofs;
reloc_type type;
} reloc_t;
struct statement_s;
reloc_t *new_reloc (int ofs, reloc_type type);
void relocate_refs (reloc_t *refs, int ofs);
#endif//__reloc_h

View file

@ -40,7 +40,7 @@ bin_PROGRAMS= qfcc
qfcc_SOURCES= \
class.c cmdlib.c cpp.c debug.c emit.c expr.c function.c idstuff.c \
immediate.c method.c opcodes.c options.c pr_def.c qc-lex.l qc-parse.y \
qfcc.c struct.c switch.c type.c
qfcc.c reloc.c struct.c switch.c type.c
qfcc_LDADD= $(QFCC_LIBS)
qfcc_DEPENDENCIES= $(QFCC_DEPS)

View file

@ -51,11 +51,26 @@ static const char rcsid[] =
#include "opcodes.h"
#include "options.h"
#include "qfcc.h"
#include "reloc.h"
#include "type.h"
#include "qc-parse.h"
def_t *emit_sub_expr (expr_t *e, def_t *dest);
void
add_statement_ref (def_t *def, dstatement_t *st, int field)
{
if (def) {
reloc_t *ref = new_reloc (st - pr.statements, field);
ref->next = def->refs;
def->refs = ref;
def->users--;
def->used = 1;
}
}
def_t *
emit_statement (int sline, opcode_t *op, def_t *var_a, def_t *var_b,
def_t *var_c)
@ -118,9 +133,9 @@ emit_statement (int sline, opcode_t *op, def_t *var_a, def_t *var_b,
var_c ? var_c->name : "", statement->c);
#endif
PR_AddStatementRef (var_a, statement, 0);
PR_AddStatementRef (var_b, statement, 1);
PR_AddStatementRef (var_c, statement, 2);
add_statement_ref (var_a, statement, 0);
add_statement_ref (var_b, statement, 1);
add_statement_ref (var_c, statement, 2);
if (op->right_associative)
return var_a;
@ -131,7 +146,7 @@ void
emit_branch (int line, opcode_t *op, expr_t *e, expr_t *l)
{
dstatement_t *st;
statref_t *ref;
reloc_t *ref;
def_t *def = 0;
int ofs;
@ -145,7 +160,7 @@ emit_branch (int line, opcode_t *op, expr_t *e, expr_t *l)
else
st->b = l->e.label.ofs - ofs;
} else {
ref = PR_NewStatref (ofs, op != op_goto);
ref = new_reloc (ofs, op == op_goto ? rel_op_a_op : rel_op_b_op);
ref->next = l->e.label.refs;
l->e.label.refs = ref;
}
@ -170,17 +185,17 @@ emit_function_call (expr_t *e, def_t *dest)
parm.type = types[extract_type (earg)];
arg = emit_sub_expr (earg, &parm);
if (earg->type != ex_expr && earg->type != ex_uexpr) {
op = PR_Opcode_Find ("=", arg, &parm, &def_void);
op = opcode_find ("=", arg, &parm, &def_void);
emit_statement (e->line, op, arg, &parm, 0);
}
}
op = PR_Opcode_Find (va ("<CALL%d>", count), &def_function, &def_void,
op = opcode_find (va ("<CALL%d>", count), &def_function, &def_void,
&def_void);
emit_statement (e->line, op, func, 0, 0);
def_ret.type = func->type->aux_type;
if (dest) {
op = PR_Opcode_Find ("=", dest, &def_ret, &def_void);
op = opcode_find ("=", dest, &def_ret, &def_void);
emit_statement (e->line, op, &def_ret, dest, 0);
return dest;
} else {
@ -223,7 +238,7 @@ emit_assign_expr (int oper, expr_t *e)
}
def_b = emit_sub_expr (e2, def_a);
if (def_b != def_a) {
op = PR_Opcode_Find (operator, def_b, def_a, &def_void);
op = opcode_find (operator, def_b, def_a, &def_void);
emit_statement (e->line, op, def_b, def_a, 0);
}
return def_a;
@ -234,11 +249,11 @@ emit_assign_expr (int oper, expr_t *e)
if (e1->type == ex_expr && extract_type (e1->e.expr.e1) == ev_pointer) {
def_a = emit_sub_expr (e1->e.expr.e1, 0);
def_c = emit_sub_expr (e1->e.expr.e2, 0);
op = PR_Opcode_Find (operator, def_b, def_a, def_c);
op = opcode_find (operator, def_b, def_a, def_c);
} else {
def_a = emit_sub_expr (e1, 0);
def_c = 0;
op = PR_Opcode_Find (operator, def_b, def_a, &def_void);
op = opcode_find (operator, def_b, def_a, &def_void);
}
emit_statement (e->line, op, def_b, def_a, def_c);
return def_b;
@ -316,7 +331,7 @@ emit_sub_expr (expr_t *e, def_t *dest)
dest = PR_GetTempDef (e->e.expr.type, pr_scope);
dest->users += 2;
}
op = PR_Opcode_Find (operator, def_a, def_b, dest);
op = opcode_find (operator, def_a, def_b, dest);
d = emit_statement (e->line, op, def_a, def_b, dest);
break;
case ex_uexpr:
@ -391,7 +406,7 @@ emit_sub_expr (expr_t *e, def_t *dest)
default:
abort ();
}
op = PR_Opcode_Find (operator, def_a, def_b, dest);
op = opcode_find (operator, def_a, def_b, dest);
d = emit_statement (e->line, op, def_a, def_b, dest);
break;
case ex_def:
@ -447,7 +462,6 @@ emit_expr (expr_t *e)
def_t *def;
def_t *def_a;
def_t *def_b;
statref_t *ref;
ex_label_t *label;
//printf ("%d ", e->line);
@ -459,24 +473,6 @@ emit_expr (expr_t *e)
case ex_label:
label = &e->e.label;
label->ofs = pr.num_statements;
for (ref = label->refs; ref; ref = ref->next) {
switch (ref->field) {
case 0:
pr.statements[ref->ofs].a = label->ofs - ref->ofs;
break;
case 1:
pr.statements[ref->ofs].b = label->ofs - ref->ofs;
break;
case 2:
pr.statements[ref->ofs].c = label->ofs - ref->ofs;
break;
case 3:
G_INT (ref->ofs) = label->ofs;
break;
default:
abort ();
}
}
break;
case ex_block:
for (e = e->e.block.head; e; e = e->next)

View file

@ -384,6 +384,8 @@ new_label_expr (void)
l->type = ex_label;
l->e.label.name = new_label_name ();
l->e.label.next = pr.labels;
pr.labels = &l->e.label;
return l;
}

View file

@ -32,10 +32,10 @@ static const char rcsid[] =
#include <QF/hash.h>
#include "qfcc.h"
#include "def.h"
#include "opcodes.h"
#include "options.h"
#include "qfcc.h"
#include "type.h"
hashtab_t *opcode_type_table_ab;
@ -54,30 +54,6 @@ opcode_t *op_goto;
opcode_t *op_jump;
opcode_t *op_jumpb;
statref_t *
PR_NewStatref (int ofs, int field)
{
statref_t *ref = calloc (1, sizeof (statref_t));
ref->ofs = ofs;
ref->field = field;
return ref;
}
void
PR_AddStatementRef (def_t *def, dstatement_t *st, int field)
{
if (def) {
statref_t *ref = PR_NewStatref (st - pr.statements, field);
ref->next = def->refs;
def->refs = ref;
def->users--;
def->used = 1;
}
}
#define ROTL(x,n) (((x)<<(n))|(x)>>(32-n))
static unsigned long
@ -120,7 +96,7 @@ compare (void *_opa, void *_opb, void *_tab)
}
opcode_t *
PR_Opcode_Find (const char *name, def_t *var_a, def_t *var_b, def_t *var_c)
opcode_find (const char *name, def_t *var_a, def_t *var_b, def_t *var_c)
{
opcode_t op;
hashtab_t **tab;
@ -142,7 +118,7 @@ PR_Opcode_Find (const char *name, def_t *var_a, def_t *var_b, def_t *var_c)
}
void
PR_Opcode_Init_Tables (void)
opcode_init (void)
{
opcode_t *op;

View file

@ -73,6 +73,7 @@ static const char rcsid[] =
#include "immediate.h"
#include "opcodes.h"
#include "options.h"
#include "reloc.h"
#include "type.h"
options_t options;
@ -311,28 +312,6 @@ PR_BeginCompilation (void)
pr_error_count = 0;
}
void
PR_RelocateRefs (def_t *def)
{
statref_t *ref;
for (ref = def->refs; ref; ref = ref->next) {
switch (ref->field) {
case 0:
pr.statements[ref->ofs].a = def->ofs;
break;
case 1:
pr.statements[ref->ofs].b = def->ofs;
break;
case 2:
pr.statements[ref->ofs].c = def->ofs;
break;
default:
abort ();
}
}
}
/*
PR_FinishCompilation
@ -346,6 +325,7 @@ qboolean PR_FinishCompilation (void)
function_t *f;
def_t *def;
expr_t e;
ex_label_t *l;
class_finish_module ();
// check to make sure all functions prototyped have code
@ -374,7 +354,7 @@ qboolean PR_FinishCompilation (void)
for (def = pr.def_head; def; def = def->def_next) {
if (def->scope || def->absolute)
continue;
PR_RelocateRefs (def);
relocate_refs (def->refs, def->ofs);
}
for (f = pr.func_head; f; f = f->next) {
@ -389,11 +369,14 @@ qboolean PR_FinishCompilation (void)
if (def->absolute)
continue;
def->ofs += pr.num_globals;
PR_RelocateRefs (def);
relocate_refs (def->refs, def->ofs);
}
}
pr.num_globals += num_localdefs;
for (l = pr.labels; l; l = l->next)
relocate_refs (l->refs, l->ofs);
return !errors;
}
@ -443,7 +426,7 @@ main (int argc, char **argv)
printf ("progs.src: %s\n", progs_src);
}
PR_Opcode_Init_Tables ();
opcode_init ();
InitData ();
init_types ();

113
tools/qfcc/source/reloc.c Normal file
View file

@ -0,0 +1,113 @@
/*
#FILENAME#
#DESCRIPTION#
Copyright (C) 2001 #AUTHOR#
Author: #AUTHOR#
Date: #DATE#
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
*/
static const char rcsid[] =
"$Id$";
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include "def.h"
#include "expr.h"
#include "qfcc.h"
#include "reloc.h"
void
relocate_refs (reloc_t *refs, int ofs)
{
int o;
while (refs) {
switch (refs->type) {
case rel_none:
break;
case rel_op_a_def:
if (ofs > 65535)
error (0, "def offset too large");
else
pr.statements[refs->ofs].a = ofs;
break;
case rel_op_b_def:
if (ofs > 65535)
error (0, "def offset too large");
else
pr.statements[refs->ofs].b = ofs;
break;
case rel_op_c_def:
if (ofs > 65535)
error (0, "def offset too large");
else
pr.statements[refs->ofs].c = ofs;
break;
case rel_op_a_op:
o = ofs - refs->ofs;
if (o < -32768 || o > 32767)
error (0, "relative offset too large");
else
pr.statements[refs->ofs].a = o;
break;
case rel_op_b_op:
o = ofs - refs->ofs;
if (o < -32768 || o > 32767)
error (0, "relative offset too large");
else
pr.statements[refs->ofs].b = o;
break;
case rel_op_c_op:
o = ofs - refs->ofs;
if (o < -32768 || o > 32767)
error (0, "relative offset too large");
else
pr.statements[refs->ofs].c = o;
break;
case rel_def_op:
if (ofs >= pr.num_statements)
error (0, "invalid statement offset");
else
G_INT (refs->ofs) = ofs;
break;
case rel_def_def:
G_INT (refs->ofs) = ofs;
break;
}
refs = refs->next;
}
}
reloc_t *
new_reloc (int ofs, reloc_type type)
{
reloc_t *ref = calloc (1, sizeof (reloc_t));
ref->ofs = ofs;
ref->type = type;
return ref;
}

View file

@ -44,13 +44,15 @@ static const char rcsid[] =
#include <QF/hash.h>
#include <QF/sys.h>
#include "qfcc.h"
#include "def.h"
#include "expr.h"
#include "opcodes.h"
#include "options.h"
#include "type.h"
#include "qfcc.h"
#include "reloc.h"
#include "switch.h"
#include "type.h"
#include "qc-parse.h"
typedef struct case_node_s {
@ -320,9 +322,9 @@ build_switch (expr_t *sw, case_node_t *tree, int op, expr_t *sw_val,
build_switch (sw, tree->right, op, sw_val, temp, default_label);
}
for (i = 0; i <= high - low; i++) {
statref_t *ref;
reloc_t *ref;
ref = PR_NewStatref (G_INT (def->ofs) + i, 3);
ref = new_reloc (G_INT (def->ofs) + i, rel_def_op);
ref->next = tree->labels[i]->e.label.refs;
tree->labels[i]->e.label.refs = ref;
}