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.
This commit is contained in:
Bill Currie 2001-11-09 00:58:16 +00:00
parent 67cec900e5
commit 928d343295
12 changed files with 263 additions and 30 deletions

View file

@ -37,6 +37,7 @@ typedef enum {
ev_pointer,
ev_quaternion,
ev_integer,
ev_uinteger,
ev_type_count // not a type, gives number of types
} etype_t;
@ -201,6 +202,18 @@ typedef enum {
OP_ADDRESS_P,
OP_LEA,
OP_IFBE,
OP_IFB,
OP_IFAE,
OP_IFA,
OP_JUMP,
OP_LT_UI,
OP_GT_UI,
OP_LE_UI,
OP_GE_UI,
} pr_opcode_e;
typedef struct

View file

@ -41,6 +41,7 @@ typedef union pr_type_u {
int entity_var;
float vector_var[1]; // really 3, but this structure must be 32 bits
int integer_var;
unsigned int uinteger_var;
} pr_type_t;
#define MAX_ENT_LEAFS 16
@ -123,6 +124,7 @@ int NUM_FOR_BAD_EDICT(progs_t *pr, edict_t *e);
#define G_FLOAT(p,o) G_var (p, o, float)
#define G_INT(p,o) G_var (p, o, integer)
#define G_UINT(p,o) G_var (p, o, uinteger)
#define G_EDICT(p,o) ((edict_t *)(PR_edicts (p) + G_INT (p, o)))
#define G_EDICTNUM(p,o) NUM_FOR_EDICT(p, G_EDICT(p, o))
#define G_VECTOR(p,o) G_var (p, o, vector)
@ -133,6 +135,7 @@ int NUM_FOR_BAD_EDICT(progs_t *pr, edict_t *e);
#define E_FLOAT(e,o) E_var (e, o, float)
#define E_INT(e,o) E_var (e, o, integer)
#define E_UINT(e,o) E_var (e, o, uinteger)
#define E_VECTOR(e,o) E_var (e, o, vector)
#define E_STRING(p,e,o) (PR_GetString (p, E_var (e, o, string)))

View file

@ -69,7 +69,8 @@ PR_PrintStatement (progs_t * pr, dstatement_t *s)
}
Sys_Printf ("%-9s ", op->opname);
if (s->op == OP_IF || s->op == OP_IFNOT)
if (s->op == OP_IF || s->op == OP_IFNOT || s->op == OP_IFBE
|| s->op == OP_IFB || s->op == OP_IFAE || s->op == OP_IFA)
Sys_Printf ("%sbranch %i (%i)",
PR_GlobalString (pr, s->a, ev_integer), s->b, addr + s->b);
else if (s->op == OP_GOTO) {
@ -594,9 +595,35 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum)
if (OPA.integer_var)
st += (short)st->b - 1; // offset the s++
break;
case OP_IFBE:
if (OPA.integer_var <= 0)
st += (short)st->b - 1; // offset the s++
break;
case OP_IFB:
if (OPA.integer_var < 0)
st += (short)st->b - 1; // offset the s++
break;
case OP_IFAE:
if (OPA.integer_var >= 0)
st += (short)st->b - 1; // offset the s++
break;
case OP_IFA:
if (OPA.integer_var > 0)
st += (short)st->b - 1; // offset the s++
break;
case OP_GOTO:
st += (short)st->a - 1; // offset the s++
break;
case OP_JUMP:
if (pr_boundscheck->int_val
&& (OPA.uinteger_var >= pr->progs->numstatements)) {
pr->pr_xstatement = st - pr->pr_statements;
PR_RunError (pr, "Invalid jump destination\n");
return;
}
st = &pr->pr_statements[OPA.uinteger_var];
break;
case OP_CALL0:
case OP_CALL1:
case OP_CALL2:
@ -690,6 +717,7 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum)
case OP_BITNOT_I:
OPC.integer_var = ~OPA.integer_var;
break;
case OP_GE_I:
OPC.integer_var = OPA.integer_var >= OPB.integer_var;
break;
@ -700,8 +728,21 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum)
OPC.integer_var = OPA.integer_var > OPB.integer_var;
break;
case OP_LT_I:
OPC.integer_var = OPA.uinteger_var < OPB.uinteger_var;
break;
case OP_GE_UI:
OPC.integer_var = OPA.uinteger_var >= OPB.uinteger_var;
break;
case OP_LE_UI:
OPC.integer_var = OPA.uinteger_var <= OPB.uinteger_var;
break;
case OP_GT_UI:
OPC.integer_var = OPA.uinteger_var > OPB.uinteger_var;
break;
case OP_LT_UI:
OPC.integer_var = OPA.integer_var < OPB.integer_var;
break;
case OP_AND_I:
OPC.integer_var = OPA.integer_var && OPB.integer_var;
break;

View file

@ -144,8 +144,12 @@ opcode_t pr_opcodes[] = {
{"!", "not.ent", OP_NOT_ENT, false, ev_entity, ev_void, ev_integer, PROG_ID_VERSION},
{"!", "not.fnc", OP_NOT_FNC, false, ev_func, ev_void, ev_integer, PROG_ID_VERSION},
{"<IF>", "if", OP_IF, false, ev_integer, ev_integer, ev_void, PROG_ID_VERSION},
{"<IFNOT>", "ifnot", OP_IFNOT, false, ev_integer, ev_integer, ev_void, PROG_ID_VERSION},
{"<IF>", "if", OP_IF, false, ev_integer, ev_void, ev_void, PROG_ID_VERSION},
{"<IFNOT>", "ifnot", OP_IFNOT, false, ev_integer, ev_void, ev_void, PROG_ID_VERSION},
{"<IFBE>", "ifbe", OP_IFBE, true, ev_integer, ev_integer, ev_void, PROG_VERSION},
{"<IFB>", "ifb", OP_IFB, true, ev_integer, ev_integer, ev_void, PROG_VERSION},
{"<IFAE>", "ifae", OP_IFAE, true, ev_integer, ev_integer, ev_void, PROG_VERSION},
{"<IFA>", "ifa", OP_IFA, true, ev_integer, ev_integer, ev_void, PROG_VERSION},
// calls returns REG_RETURN
{"<CALL0>", "call0", OP_CALL0, false, ev_func, ev_void, ev_void, PROG_ID_VERSION},
@ -160,7 +164,8 @@ opcode_t pr_opcodes[] = {
{"<STATE>", "state", OP_STATE, false, ev_float, ev_float, ev_void, PROG_ID_VERSION},
{"<GOTO>", "goto", OP_GOTO, false, ev_float, ev_void, ev_void, PROG_ID_VERSION},
{"<GOTO>", "goto", OP_GOTO, false, ev_integer, ev_void, ev_void, PROG_ID_VERSION},
{"<JUMP>", "jump", OP_JUMP, false, ev_integer, ev_void, ev_void, PROG_VERSION},
{"&&", "and", OP_AND, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION},
{"||", "or", OP_OR, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION},
@ -181,10 +186,17 @@ opcode_t pr_opcodes[] = {
{"%", "mod.f", OP_MOD_F, false, ev_float, ev_float, ev_float, PROG_VERSION},
{"&", "bitand.i", OP_BITAND_I, false, ev_integer, ev_integer, ev_integer, PROG_VERSION},
{"|", "bitor.i", OP_BITOR_I, false, ev_integer, ev_integer, ev_integer, PROG_VERSION},
{">=", "ge.i", OP_GE_I, false, ev_integer, ev_integer, ev_integer, PROG_VERSION},
{"<=", "le.i", OP_LE_I, false, ev_integer, ev_integer, ev_integer, PROG_VERSION},
{">", "gt.i", OP_GT_I, false, ev_integer, ev_integer, ev_integer, PROG_VERSION},
{"<", "lt.i", OP_LT_I, false, ev_integer, ev_integer, ev_integer, PROG_VERSION},
{">=", "ge.ui", OP_GE_UI, false, ev_uinteger, ev_uinteger, ev_integer, PROG_VERSION},
{"<=", "le.ui", OP_LE_UI, false, ev_uinteger, ev_uinteger, ev_integer, PROG_VERSION},
{">", "gt.ui", OP_GT_UI, false, ev_uinteger, ev_uinteger, ev_integer, PROG_VERSION},
{"<", "lt.ui", OP_LT_UI, false, ev_uinteger, ev_uinteger, ev_integer, PROG_VERSION},
{"&&", "and.i", OP_AND_I, false, ev_integer, ev_integer, ev_integer, PROG_VERSION},
{"||", "or.i", OP_OR_I, false, ev_integer, ev_integer, ev_integer, PROG_VERSION},
{"!", "not.i", OP_NOT_I, false, ev_integer, ev_void, ev_integer, PROG_VERSION},

View file

@ -82,6 +82,8 @@ expr_t *new_binary_expr (int op, expr_t *e1, expr_t *e2);
expr_t *new_unary_expr (int op, expr_t *e1);
expr_t *new_temp_def_expr (type_t *type);
void inc_users (expr_t *e);
expr_t *append_expr (expr_t *block, expr_t *e);
void print_expr (expr_t *e);

View file

@ -392,6 +392,10 @@ 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;

View file

@ -159,6 +159,10 @@ emit_assign_expr (expr_t *e)
expr_t *e1 = e->e.expr.e1;
expr_t *e2 = e->e.expr.e2;
if (e1->type == ex_temp && e1->e.temp.users < 2) {
e1->e.temp.users--;
return 0;
}
def_a = emit_sub_expr (e1, 0);
if (def_a->type->type == ev_pointer) {
def_b = emit_sub_expr (e2, 0);
@ -335,6 +339,18 @@ emit_expr (expr_t *e)
case 'i':
emit_branch (e->line, op_if, e->e.expr.e1, e->e.expr.e2);
break;
case IFBE:
emit_branch (e->line, op_ifbe, e->e.expr.e1, e->e.expr.e2);
break;
case IFB:
emit_branch (e->line, op_ifb, e->e.expr.e1, e->e.expr.e2);
break;
case IFAE:
emit_branch (e->line, op_ifae, e->e.expr.e1, e->e.expr.e2);
break;
case IFA:
emit_branch (e->line, op_ifa, e->e.expr.e1, e->e.expr.e2);
break;
case 'c':
emit_function_call (e, 0);
break;

View file

@ -213,6 +213,10 @@ get_op_string (int op)
case '.': return ".";
case 'i': return "<if>";
case 'n': return "<ifnot>";
case IFBE: return "<ifbe>";
case IFB: return "<ifb>";
case IFAE: return "<ifae>";
case IFA: return "<ifa>";
case 'g': return "<goto>";
case 'r': return "<return>";
case 'b': return "<bind>";
@ -358,6 +362,11 @@ append_expr (expr_t *block, expr_t *e)
if (!e)
return block;
if (e->next) {
error (e, "append_expr: expr loop detected");
abort ();
}
*block->e.block.tail = e;
block->e.block.tail = &e->next;
@ -784,6 +793,7 @@ test_expr (expr_t *e, int test)
new = new_expr ();
new->type = ex_string;
break;
case ev_uinteger:
case ev_integer:
return e;
case ev_float:
@ -843,6 +853,11 @@ binary_expr (int op, expr_t *e1, expr_t *e2)
check_initialized (e1);
check_initialized (e2);
if (e1->type != ex_block)
inc_users (e1);
if (e2->type != ex_block)
inc_users (e2);
if (op == '=' && e1->type == ex_def)
PR_DefInitialized (e1->e.def);
@ -850,7 +865,6 @@ binary_expr (int op, expr_t *e1, expr_t *e2)
&& e2->type == ex_block && e2->e.block.is_call
&& e1->e.block.result) {
e = new_temp_def_expr (e1->e.block.result->e.def->type);
inc_users (e);
e1 = binary_expr ('=', e, e1);
}
@ -1322,14 +1336,12 @@ incop_expr (int op, expr_t *e, int postop)
incop = asx_expr (op, e, one);
if (postop) {
expr_t *temp;
type_t *type;
type_t *type = get_type (e);
expr_t *block = new_block_expr ();
type = e->type == ex_def
? e->e.def->type
: e->e.expr.type;
temp = new_temp_def_expr (type);
append_expr (block, binary_expr ('=', temp, e));
temp->e.temp.users = 1;
append_expr (block, incop);
block->e.block.result = temp;
return block;

View file

@ -242,6 +242,8 @@ PR_FreeTempDefs (void)
d = *def;
*def = d->next;
if (d->users < 0)
printf ("%s:%d: warning: %3d %3d\n", strings + d->file, d->line, d->ofs, d->users);
size = type_size[d->type->type];
if (d->expr)
d->expr->e.temp.def = 0;
@ -265,7 +267,7 @@ PR_ResetTempDefs (void)
}
for (d = temp_scope.next; d; d = d->next)
printf ("%3d %3d\n", d->ofs, d->users);
printf ("%s:%d: warning: %3d %3d\n", strings + d->file, d->line, d->ofs, d->users);
temp_scope.next = 0;
}

View file

@ -34,6 +34,10 @@ opcode_t *op_done;
opcode_t *op_return;
opcode_t *op_if;
opcode_t *op_ifnot;
opcode_t *op_ifbe;
opcode_t *op_ifb;
opcode_t *op_ifae;
opcode_t *op_ifa;
opcode_t *op_state;
opcode_t *op_goto;
@ -151,6 +155,14 @@ PR_Opcode_Init_Tables (void)
op_if = op;
} else if (!strcmp (op->name, "<IFNOT>")) {
op_ifnot = op;
} else if (!strcmp (op->name, "<IFBE>")) {
op_ifbe = op;
} else if (!strcmp (op->name, "<IFB>")) {
op_ifb = op;
} else if (!strcmp (op->name, "<IFAE>")) {
op_ifae = op;
} else if (!strcmp (op->name, "<IFA>")) {
op_ifa = op;
} else if (!strcmp (op->name, "<STATE>")) {
op_state = op;
} else if (!strcmp (op->name, "<GOTO>")) {

View file

@ -108,6 +108,7 @@ typedef struct {
%token <quaternion_val> QUATERNION_VAL
%token LOCAL RETURN WHILE DO IF ELSE FOR BREAK CONTINUE ELIPSIS NIL
%token IFBE IFB IFAE IFA
%token SWITCH CASE DEFAULT
%token <type> TYPE

View file

@ -43,7 +43,7 @@ get_hash (void *_cl, void *unused)
{
case_label_t *cl = (case_label_t*)_cl;
return (unsigned long)cl->value;
return cl->value ? cl->value->e.integer_val : 0;
}
static int
@ -51,8 +51,14 @@ compare (void *_cla, void *_clb, void *unused)
{
case_label_t *cla = (case_label_t*)_cla;
case_label_t *clb = (case_label_t*)_clb;
expr_t *v1 = cla->value;
expr_t *v2 = clb->value;
return cla->value == clb->value;
if (v1 == v2)
return 1;
if ((v1 && !v2) || (!v1 && v2))
return 0;
return v1->e.integer_val == v2->e.integer_val;
}
struct expr_s *
@ -74,9 +80,11 @@ case_label_expr (switch_block_t *switch_block, expr_t *value)
return 0;
}
cl->value = value;
print_expr(value);puts("");
if (Hash_FindElement (switch_block->labels, cl)) {
error (value, "duplicate %s", value ? "case" : "default");
free (cl);
return 0;
}
cl->label = new_label_expr ();
Hash_AddElement (switch_block->labels, cl);
@ -95,6 +103,83 @@ new_switch_block (void)
return switch_block;
}
static int
label_compare (const void *_a, const void *_b)
{
const case_label_t **a = (const case_label_t **)_a;
const case_label_t **b = (const case_label_t **)_b;
const char *s1, *s2;
switch ((*a)->value->type) {
case ex_string:
s1 = (*a)->value->e.string_val ? (*a)->value->e.string_val : "";
s2 = (*b)->value->e.string_val ? (*b)->value->e.string_val : "";
return strcmp (s1, s2);
break;
case ex_float:
return (*a)->value->e.float_val - (*b)->value->e.float_val;
break;
case ex_integer:
return (*a)->value->e.integer_val - (*b)->value->e.integer_val;
break;
default:
error (0, "internal compiler error in switch");
abort ();
}
}
static void
build_binary_jump_table (expr_t *sw, case_label_t **labels, int op, int base, int count, expr_t *sw_val, expr_t *temp, expr_t *default_label)
{
case_label_t *l;
expr_t *test;
expr_t *branch;
int index;
index = count / 2;
l = labels [base + index];
test = binary_expr (op, l->value, sw_val);
test->line = sw_val->line;
test->file = sw_val->file;
test = binary_expr ('=', temp, test);
test->line = sw_val->line;
test->file = sw_val->file;
branch = new_binary_expr ('n', test, l->label);
branch->line = sw_val->line;
branch->file = sw_val->file;
append_expr (sw, branch);
if (index) {
expr_t *high_label;
if (count - (index + 1)) {
high_label = new_label_expr ();
high_label->line = sw_val->line;
high_label->file = sw_val->file;
} else {
high_label = default_label;
}
branch = new_binary_expr (IFA, temp, high_label);
branch->line = sw_val->line;
branch->file = sw_val->file;
append_expr (sw, branch);
build_binary_jump_table (sw, labels, op, base, index, sw_val, temp, default_label);
if (count - (index + 1))
append_expr (sw, high_label);
}
base += index + 1;
count -= index + 1;
if (count)
build_binary_jump_table (sw, labels, op, base, count, sw_val, temp, default_label);
}
struct expr_s *
switch_expr (switch_block_t *switch_block, expr_t *break_label,
expr_t *statements)
@ -104,32 +189,62 @@ switch_expr (switch_block_t *switch_block, expr_t *break_label,
case_label_t *default_label = &_default_label;
expr_t *sw = new_block_expr ();
type_t *type = get_type (switch_block->test);
expr_t *temp = new_temp_def_expr (type);
expr_t *sw_val = new_temp_def_expr (type);
expr_t *default_expr;
int num_labels = 0;
temp->line = switch_block->test->line;
temp->file = switch_block->test->file;
sw_val->line = switch_block->test->line;
sw_val->file = switch_block->test->file;
default_label->value = 0;
default_label = Hash_DelElement (switch_block->labels, default_label);
labels = (case_label_t **)Hash_GetList (switch_block->labels);
if (default_label)
default_expr = new_unary_expr ('g', default_label->label);
else
default_expr = new_unary_expr ('g', break_label);
default_expr->line = temp->line;
default_expr->file = temp->file;
if (!default_label) {
default_label = &_default_label;
default_label->label = break_label;
}
default_expr = new_unary_expr ('g', default_label->label);
default_expr->line = sw_val->line;
default_expr->file = sw_val->file;
append_expr (sw, binary_expr ('b', switch_block->test, temp));
for (l = labels; *l; l++) {
expr_t *cmp = binary_expr (EQ, temp, (*l)->value);
expr_t *test = new_binary_expr ('i',
test_expr (cmp, 1),
(*l)->label);
test->line = cmp->line = temp->line;
test->file = cmp->file = temp->file;
append_expr (sw, test);
append_expr (sw, binary_expr ('b', switch_block->test, sw_val));
for (l = labels; *l; l++)
num_labels++;
if (options.code.progsversion == PROG_ID_VERSION
|| (type->type != ev_string
&& type->type != ev_float
&& type->type != ev_integer)
|| num_labels < 8) {
for (l = labels; *l; l++) {
expr_t *cmp = binary_expr (EQ, sw_val, (*l)->value);
expr_t *test = new_binary_expr ('i',
test_expr (cmp, 1),
(*l)->label);
test->line = cmp->line = sw_val->line;
test->file = cmp->file = sw_val->file;
append_expr (sw, test);
}
} else {
expr_t *temp = new_temp_def_expr (type);
int op;
qsort (labels, num_labels, sizeof (*labels), label_compare);
switch (type->type) {
case ev_string:
op = NE;
break;
case ev_float:
op = '-';
break;
case ev_integer:
op = '-';
break;
default:
error (0, "internal compiler error in switch");
abort ();
}
build_binary_jump_table (sw, labels, op, 0, num_labels, sw_val, temp, default_label->label);
}
append_expr (sw, default_expr);
append_expr (sw, statements);