mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +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_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
|
||||
|
|
|
@ -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)))
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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>")) {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue