mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-14 00:40:55 +00:00
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:
parent
67cec900e5
commit
928d343295
12 changed files with 263 additions and 30 deletions
|
@ -37,6 +37,7 @@ typedef enum {
|
||||||
ev_pointer,
|
ev_pointer,
|
||||||
ev_quaternion,
|
ev_quaternion,
|
||||||
ev_integer,
|
ev_integer,
|
||||||
|
ev_uinteger,
|
||||||
|
|
||||||
ev_type_count // not a type, gives number of types
|
ev_type_count // not a type, gives number of types
|
||||||
} etype_t;
|
} etype_t;
|
||||||
|
@ -201,6 +202,18 @@ typedef enum {
|
||||||
OP_ADDRESS_P,
|
OP_ADDRESS_P,
|
||||||
|
|
||||||
OP_LEA,
|
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;
|
} pr_opcode_e;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|
|
@ -41,6 +41,7 @@ typedef union pr_type_u {
|
||||||
int entity_var;
|
int entity_var;
|
||||||
float vector_var[1]; // really 3, but this structure must be 32 bits
|
float vector_var[1]; // really 3, but this structure must be 32 bits
|
||||||
int integer_var;
|
int integer_var;
|
||||||
|
unsigned int uinteger_var;
|
||||||
} pr_type_t;
|
} pr_type_t;
|
||||||
|
|
||||||
#define MAX_ENT_LEAFS 16
|
#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_FLOAT(p,o) G_var (p, o, float)
|
||||||
#define G_INT(p,o) G_var (p, o, integer)
|
#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_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_EDICTNUM(p,o) NUM_FOR_EDICT(p, G_EDICT(p, o))
|
||||||
#define G_VECTOR(p,o) G_var (p, o, vector)
|
#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_FLOAT(e,o) E_var (e, o, float)
|
||||||
#define E_INT(e,o) E_var (e, o, integer)
|
#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_VECTOR(e,o) E_var (e, o, vector)
|
||||||
#define E_STRING(p,e,o) (PR_GetString (p, E_var (e, o, string)))
|
#define E_STRING(p,e,o) (PR_GetString (p, E_var (e, o, string)))
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,8 @@ PR_PrintStatement (progs_t * pr, dstatement_t *s)
|
||||||
}
|
}
|
||||||
Sys_Printf ("%-9s ", op->opname);
|
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)",
|
Sys_Printf ("%sbranch %i (%i)",
|
||||||
PR_GlobalString (pr, s->a, ev_integer), s->b, addr + s->b);
|
PR_GlobalString (pr, s->a, ev_integer), s->b, addr + s->b);
|
||||||
else if (s->op == OP_GOTO) {
|
else if (s->op == OP_GOTO) {
|
||||||
|
@ -594,9 +595,35 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum)
|
||||||
if (OPA.integer_var)
|
if (OPA.integer_var)
|
||||||
st += (short)st->b - 1; // offset the s++
|
st += (short)st->b - 1; // offset the s++
|
||||||
break;
|
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:
|
case OP_GOTO:
|
||||||
st += (short)st->a - 1; // offset the s++
|
st += (short)st->a - 1; // offset the s++
|
||||||
break;
|
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_CALL0:
|
||||||
case OP_CALL1:
|
case OP_CALL1:
|
||||||
case OP_CALL2:
|
case OP_CALL2:
|
||||||
|
@ -690,6 +717,7 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum)
|
||||||
case OP_BITNOT_I:
|
case OP_BITNOT_I:
|
||||||
OPC.integer_var = ~OPA.integer_var;
|
OPC.integer_var = ~OPA.integer_var;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_GE_I:
|
case OP_GE_I:
|
||||||
OPC.integer_var = OPA.integer_var >= OPB.integer_var;
|
OPC.integer_var = OPA.integer_var >= OPB.integer_var;
|
||||||
break;
|
break;
|
||||||
|
@ -700,8 +728,21 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum)
|
||||||
OPC.integer_var = OPA.integer_var > OPB.integer_var;
|
OPC.integer_var = OPA.integer_var > OPB.integer_var;
|
||||||
break;
|
break;
|
||||||
case OP_LT_I:
|
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;
|
OPC.integer_var = OPA.integer_var < OPB.integer_var;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_AND_I:
|
case OP_AND_I:
|
||||||
OPC.integer_var = OPA.integer_var && OPB.integer_var;
|
OPC.integer_var = OPA.integer_var && OPB.integer_var;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -144,8 +144,12 @@ opcode_t pr_opcodes[] = {
|
||||||
{"!", "not.ent", OP_NOT_ENT, false, ev_entity, ev_void, ev_integer, PROG_ID_VERSION},
|
{"!", "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},
|
{"!", "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},
|
{"<IF>", "if", OP_IF, false, ev_integer, ev_void, ev_void, PROG_ID_VERSION},
|
||||||
{"<IFNOT>", "ifnot", OP_IFNOT, false, ev_integer, ev_integer, 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
|
// calls returns REG_RETURN
|
||||||
{"<CALL0>", "call0", OP_CALL0, false, ev_func, ev_void, ev_void, PROG_ID_VERSION},
|
{"<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},
|
{"<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},
|
{"&&", "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},
|
{"||", "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},
|
{"%", "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},
|
{"&", "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},
|
{"|", "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},
|
{">=", "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},
|
{"<=", "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},
|
{">", "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},
|
{"<", "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},
|
{"&&", "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},
|
{"||", "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},
|
{"!", "not.i", OP_NOT_I, false, ev_integer, ev_void, ev_integer, PROG_VERSION},
|
||||||
|
|
|
@ -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_unary_expr (int op, expr_t *e1);
|
||||||
expr_t *new_temp_def_expr (type_t *type);
|
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);
|
expr_t *append_expr (expr_t *block, expr_t *e);
|
||||||
|
|
||||||
void print_expr (expr_t *e);
|
void print_expr (expr_t *e);
|
||||||
|
|
|
@ -392,6 +392,10 @@ extern opcode_t *op_done;
|
||||||
extern opcode_t *op_return;
|
extern opcode_t *op_return;
|
||||||
extern opcode_t *op_if;
|
extern opcode_t *op_if;
|
||||||
extern opcode_t *op_ifnot;
|
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_state;
|
||||||
extern opcode_t *op_goto;
|
extern opcode_t *op_goto;
|
||||||
|
|
||||||
|
|
|
@ -159,6 +159,10 @@ emit_assign_expr (expr_t *e)
|
||||||
expr_t *e1 = e->e.expr.e1;
|
expr_t *e1 = e->e.expr.e1;
|
||||||
expr_t *e2 = e->e.expr.e2;
|
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);
|
def_a = emit_sub_expr (e1, 0);
|
||||||
if (def_a->type->type == ev_pointer) {
|
if (def_a->type->type == ev_pointer) {
|
||||||
def_b = emit_sub_expr (e2, 0);
|
def_b = emit_sub_expr (e2, 0);
|
||||||
|
@ -335,6 +339,18 @@ emit_expr (expr_t *e)
|
||||||
case 'i':
|
case 'i':
|
||||||
emit_branch (e->line, op_if, e->e.expr.e1, e->e.expr.e2);
|
emit_branch (e->line, op_if, e->e.expr.e1, e->e.expr.e2);
|
||||||
break;
|
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':
|
case 'c':
|
||||||
emit_function_call (e, 0);
|
emit_function_call (e, 0);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -213,6 +213,10 @@ get_op_string (int op)
|
||||||
case '.': return ".";
|
case '.': return ".";
|
||||||
case 'i': return "<if>";
|
case 'i': return "<if>";
|
||||||
case 'n': return "<ifnot>";
|
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 'g': return "<goto>";
|
||||||
case 'r': return "<return>";
|
case 'r': return "<return>";
|
||||||
case 'b': return "<bind>";
|
case 'b': return "<bind>";
|
||||||
|
@ -358,6 +362,11 @@ append_expr (expr_t *block, expr_t *e)
|
||||||
if (!e)
|
if (!e)
|
||||||
return block;
|
return block;
|
||||||
|
|
||||||
|
if (e->next) {
|
||||||
|
error (e, "append_expr: expr loop detected");
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
|
||||||
*block->e.block.tail = e;
|
*block->e.block.tail = e;
|
||||||
block->e.block.tail = &e->next;
|
block->e.block.tail = &e->next;
|
||||||
|
|
||||||
|
@ -784,6 +793,7 @@ test_expr (expr_t *e, int test)
|
||||||
new = new_expr ();
|
new = new_expr ();
|
||||||
new->type = ex_string;
|
new->type = ex_string;
|
||||||
break;
|
break;
|
||||||
|
case ev_uinteger:
|
||||||
case ev_integer:
|
case ev_integer:
|
||||||
return e;
|
return e;
|
||||||
case ev_float:
|
case ev_float:
|
||||||
|
@ -843,6 +853,11 @@ binary_expr (int op, expr_t *e1, expr_t *e2)
|
||||||
check_initialized (e1);
|
check_initialized (e1);
|
||||||
check_initialized (e2);
|
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)
|
if (op == '=' && e1->type == ex_def)
|
||||||
PR_DefInitialized (e1->e.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
|
&& e2->type == ex_block && e2->e.block.is_call
|
||||||
&& e1->e.block.result) {
|
&& e1->e.block.result) {
|
||||||
e = new_temp_def_expr (e1->e.block.result->e.def->type);
|
e = new_temp_def_expr (e1->e.block.result->e.def->type);
|
||||||
inc_users (e);
|
|
||||||
e1 = binary_expr ('=', e, e1);
|
e1 = binary_expr ('=', e, e1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1322,14 +1336,12 @@ incop_expr (int op, expr_t *e, int postop)
|
||||||
incop = asx_expr (op, e, one);
|
incop = asx_expr (op, e, one);
|
||||||
if (postop) {
|
if (postop) {
|
||||||
expr_t *temp;
|
expr_t *temp;
|
||||||
type_t *type;
|
type_t *type = get_type (e);
|
||||||
expr_t *block = new_block_expr ();
|
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);
|
temp = new_temp_def_expr (type);
|
||||||
append_expr (block, binary_expr ('=', temp, e));
|
append_expr (block, binary_expr ('=', temp, e));
|
||||||
|
temp->e.temp.users = 1;
|
||||||
append_expr (block, incop);
|
append_expr (block, incop);
|
||||||
block->e.block.result = temp;
|
block->e.block.result = temp;
|
||||||
return block;
|
return block;
|
||||||
|
|
|
@ -242,6 +242,8 @@ PR_FreeTempDefs (void)
|
||||||
d = *def;
|
d = *def;
|
||||||
*def = d->next;
|
*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];
|
size = type_size[d->type->type];
|
||||||
if (d->expr)
|
if (d->expr)
|
||||||
d->expr->e.temp.def = 0;
|
d->expr->e.temp.def = 0;
|
||||||
|
@ -265,7 +267,7 @@ PR_ResetTempDefs (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (d = temp_scope.next; d; d = d->next)
|
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;
|
temp_scope.next = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,10 @@ opcode_t *op_done;
|
||||||
opcode_t *op_return;
|
opcode_t *op_return;
|
||||||
opcode_t *op_if;
|
opcode_t *op_if;
|
||||||
opcode_t *op_ifnot;
|
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_state;
|
||||||
opcode_t *op_goto;
|
opcode_t *op_goto;
|
||||||
|
|
||||||
|
@ -151,6 +155,14 @@ PR_Opcode_Init_Tables (void)
|
||||||
op_if = op;
|
op_if = op;
|
||||||
} else if (!strcmp (op->name, "<IFNOT>")) {
|
} else if (!strcmp (op->name, "<IFNOT>")) {
|
||||||
op_ifnot = op;
|
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>")) {
|
} else if (!strcmp (op->name, "<STATE>")) {
|
||||||
op_state = op;
|
op_state = op;
|
||||||
} else if (!strcmp (op->name, "<GOTO>")) {
|
} else if (!strcmp (op->name, "<GOTO>")) {
|
||||||
|
|
|
@ -108,6 +108,7 @@ typedef struct {
|
||||||
%token <quaternion_val> QUATERNION_VAL
|
%token <quaternion_val> QUATERNION_VAL
|
||||||
|
|
||||||
%token LOCAL RETURN WHILE DO IF ELSE FOR BREAK CONTINUE ELIPSIS NIL
|
%token LOCAL RETURN WHILE DO IF ELSE FOR BREAK CONTINUE ELIPSIS NIL
|
||||||
|
%token IFBE IFB IFAE IFA
|
||||||
%token SWITCH CASE DEFAULT
|
%token SWITCH CASE DEFAULT
|
||||||
%token <type> TYPE
|
%token <type> TYPE
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ get_hash (void *_cl, void *unused)
|
||||||
{
|
{
|
||||||
case_label_t *cl = (case_label_t*)_cl;
|
case_label_t *cl = (case_label_t*)_cl;
|
||||||
|
|
||||||
return (unsigned long)cl->value;
|
return cl->value ? cl->value->e.integer_val : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -51,8 +51,14 @@ compare (void *_cla, void *_clb, void *unused)
|
||||||
{
|
{
|
||||||
case_label_t *cla = (case_label_t*)_cla;
|
case_label_t *cla = (case_label_t*)_cla;
|
||||||
case_label_t *clb = (case_label_t*)_clb;
|
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 *
|
struct expr_s *
|
||||||
|
@ -74,9 +80,11 @@ case_label_expr (switch_block_t *switch_block, expr_t *value)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
cl->value = value;
|
cl->value = value;
|
||||||
|
print_expr(value);puts("");
|
||||||
if (Hash_FindElement (switch_block->labels, cl)) {
|
if (Hash_FindElement (switch_block->labels, cl)) {
|
||||||
error (value, "duplicate %s", value ? "case" : "default");
|
error (value, "duplicate %s", value ? "case" : "default");
|
||||||
free (cl);
|
free (cl);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
cl->label = new_label_expr ();
|
cl->label = new_label_expr ();
|
||||||
Hash_AddElement (switch_block->labels, cl);
|
Hash_AddElement (switch_block->labels, cl);
|
||||||
|
@ -95,6 +103,83 @@ new_switch_block (void)
|
||||||
return switch_block;
|
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 *
|
struct expr_s *
|
||||||
switch_expr (switch_block_t *switch_block, expr_t *break_label,
|
switch_expr (switch_block_t *switch_block, expr_t *break_label,
|
||||||
expr_t *statements)
|
expr_t *statements)
|
||||||
|
@ -104,33 +189,63 @@ switch_expr (switch_block_t *switch_block, expr_t *break_label,
|
||||||
case_label_t *default_label = &_default_label;
|
case_label_t *default_label = &_default_label;
|
||||||
expr_t *sw = new_block_expr ();
|
expr_t *sw = new_block_expr ();
|
||||||
type_t *type = get_type (switch_block->test);
|
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;
|
expr_t *default_expr;
|
||||||
|
int num_labels = 0;
|
||||||
|
|
||||||
temp->line = switch_block->test->line;
|
sw_val->line = switch_block->test->line;
|
||||||
temp->file = switch_block->test->file;
|
sw_val->file = switch_block->test->file;
|
||||||
|
|
||||||
default_label->value = 0;
|
default_label->value = 0;
|
||||||
default_label = Hash_DelElement (switch_block->labels, default_label);
|
default_label = Hash_DelElement (switch_block->labels, default_label);
|
||||||
labels = (case_label_t **)Hash_GetList (switch_block->labels);
|
labels = (case_label_t **)Hash_GetList (switch_block->labels);
|
||||||
|
|
||||||
if (default_label)
|
if (!default_label) {
|
||||||
|
default_label = &_default_label;
|
||||||
|
default_label->label = break_label;
|
||||||
|
}
|
||||||
default_expr = new_unary_expr ('g', default_label->label);
|
default_expr = new_unary_expr ('g', default_label->label);
|
||||||
else
|
default_expr->line = sw_val->line;
|
||||||
default_expr = new_unary_expr ('g', break_label);
|
default_expr->file = sw_val->file;
|
||||||
default_expr->line = temp->line;
|
|
||||||
default_expr->file = temp->file;
|
|
||||||
|
|
||||||
append_expr (sw, binary_expr ('b', switch_block->test, temp));
|
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++) {
|
for (l = labels; *l; l++) {
|
||||||
expr_t *cmp = binary_expr (EQ, temp, (*l)->value);
|
expr_t *cmp = binary_expr (EQ, sw_val, (*l)->value);
|
||||||
expr_t *test = new_binary_expr ('i',
|
expr_t *test = new_binary_expr ('i',
|
||||||
test_expr (cmp, 1),
|
test_expr (cmp, 1),
|
||||||
(*l)->label);
|
(*l)->label);
|
||||||
test->line = cmp->line = temp->line;
|
test->line = cmp->line = sw_val->line;
|
||||||
test->file = cmp->file = temp->file;
|
test->file = cmp->file = sw_val->file;
|
||||||
append_expr (sw, test);
|
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, default_expr);
|
||||||
append_expr (sw, statements);
|
append_expr (sw, statements);
|
||||||
append_expr (sw, break_label);
|
append_expr (sw, break_label);
|
||||||
|
|
Loading…
Reference in a new issue