Rework build_switch to use initialize_def.

This required support for label reference expressions, whose purpose is to
represent the address of a label.
This commit is contained in:
Bill Currie 2012-11-03 18:08:32 +09:00
parent 48fe9f729d
commit 9095e1eabc
7 changed files with 78 additions and 21 deletions

View file

@ -45,6 +45,7 @@ typedef enum {
ex_state, ///< state expression (::ex_state_t)
ex_bool, ///< short circuit boolean logic expression (::ex_bool_t)
ex_label, ///< goto/branch label (::ex_label_t)
ex_labelref, ///< label reference (::ex_labelref_t)
ex_block, ///< statement block expression (::ex_block_t)
ex_expr, ///< binary expression (::ex_expr_t)
ex_uexpr, ///< unary expression (::ex_expr_t)
@ -69,13 +70,17 @@ typedef struct ex_expr_s {
} ex_expr_t;
typedef struct ex_label_s {
struct ex_label_s *next; ///< next label in global list of labels
struct ex_label_s *next;
struct reloc_s *refs; ///< relocations associated with this label
struct sblock_s *dest; ///< the location of this label if known
const char *name; ///< the name of this label
int used; ///< label is used as a target
} ex_label_t;
typedef struct {
ex_label_t *label;
} ex_labelref_t;
typedef struct {
struct expr_s *head; ///< the first expression in the block
struct expr_s **tail; ///< last expression in the block, for appending
@ -179,6 +184,7 @@ typedef struct expr_s {
unsigned rvalue:1; ///< the expression is on the right side of =
union {
ex_label_t label; ///< label expression
ex_labelref_t labelref; ///< label reference expression (&)
ex_state_t state; ///< state expression
ex_bool_t bool; ///< boolean logic expression
ex_block_t block; ///< statement block expression
@ -253,13 +259,21 @@ const char *new_label_name (void);
/** Create a new label expression node.
The label name is set using new_label_name(), and the label is linked
into the global list of labels for later resolution.
The label name is set using new_label_name().
\return The new label expression (::ex_label_t) node.
*/
expr_t *new_label_expr (void);
/** Create a new label reference expression node.
Used for taking the address of a label (eg. jump tables).
The label's \a used field is incremented.
\return The new label reference expression (::ex_labelref_t) node.
*/
expr_t *new_label_ref (ex_label_t *label);
/** Create a new state expression node.
The label name is set using new_label_name(), and the label is linked

View file

@ -1469,7 +1469,7 @@ fold_constants (expr_t *e)
if (e2->type == ex_error)
return e2;
if (e2->type == ex_label)
if (e2->type == ex_label || e2->type == ex_labelref)
return e;
t2 = extract_type (e2);

View file

@ -277,6 +277,12 @@ init_elements (struct def_s *def, expr_t *eles)
}
init_elements (&elements[i], c);
continue;
} else if (c->type == ex_labelref) {
def_t loc;
loc.space = elements[i].space;
loc.offset = elements[i].offset;
reloc_def_op (c->e.labelref.label, &loc);
continue;
} else if (c->type == ex_value) {
if (c->e.value.type == ev_integer
&& elements[i].type->type == ev_float)

View file

@ -155,6 +155,19 @@ print_label (expr_t *e, int level, int id)
e->e.label.name, e->line);
}
static void
print_labelref (expr_t *e, int level, int id)
{
int indent = level * 2 + 2;
if (e->next)
printf ("%*s\"e_%p\" -> \"e_%p\" "
"[constraint=false,style=dashed];\n", indent, "",
e, e->next);
printf ("%*s\"e_%p\" [label=\"&%s\\n%d\"];\n", indent, "", e,
e->e.label.name, e->line);
}
static void
print_block (expr_t *e, int level, int id)
{
@ -364,6 +377,7 @@ _print_expr (expr_t *e, int level, int id)
print_state,
print_bool,
print_label,
print_labelref,
print_block,
print_subexpr,
print_uexpr,

View file

@ -140,6 +140,8 @@ get_type (expr_t *e)
{
convert_name (e);
switch (e->type) {
case ex_labelref:
return &type_void;
case ex_label:
case ex_error:
return 0; // something went very wrong
@ -306,6 +308,8 @@ copy_expr (expr_t *e)
case ex_label:
/// Create a fresh label
return new_label_expr ();
case ex_labelref:
return new_label_ref (e->e.labelref.label);
case ex_block:
n = new_expr ();
*n = *e;
@ -407,6 +411,18 @@ new_label_expr (void)
return l;
}
expr_t *
new_label_ref (ex_label_t *label)
{
expr_t *l = new_expr ();
l->type = ex_labelref;
l->e.labelref.label = label;
label->used++;
return l;
}
expr_t *
new_block_expr (void)
{
@ -607,7 +623,7 @@ new_short_expr (short short_val)
int
is_constant (expr_t *e)
{
if (e->type == ex_nil || e->type == ex_value
if (e->type == ex_nil || e->type == ex_value || e->type == ex_labelref
|| (e->type == ex_symbol && e->e.symbol->sy_type == sy_const)
|| (e->type == ex_symbol && e->e.symbol->sy_type == sy_var
&& e->e.symbol->s.def->constant))
@ -624,7 +640,7 @@ constant_expr (expr_t *e)
if (!is_constant (e))
return e;
if (e->type == ex_nil || e->type == ex_value)
if (e->type == ex_nil || e->type == ex_value || e->type == ex_labelref)
return e;
if (e->type != ex_symbol)
return e;
@ -1623,6 +1639,7 @@ unary_expr (int op, expr_t *e)
case ex_value: // should be handled above
case ex_error:
case ex_label:
case ex_labelref:
case ex_state:
internal_error (e, 0);
case ex_uexpr:
@ -1685,6 +1702,7 @@ unary_expr (int op, expr_t *e)
case ex_value: // should be handled above
case ex_error:
case ex_label:
case ex_labelref:
case ex_state:
internal_error (e, 0);
case ex_bool:
@ -1742,6 +1760,7 @@ unary_expr (int op, expr_t *e)
case ex_value: // should be handled above
case ex_error:
case ex_label:
case ex_labelref:
case ex_state:
internal_error (e, 0);
case ex_uexpr:
@ -2217,6 +2236,8 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t)
return error (e1, "invalid type for unary &");
e1->e.block.result = address_expr (e1->e.block.result, e2, t);
return e1;
case ex_label:
return new_label_ref (&e1->e.label);
default:
return error (e1, "invalid type for unary &");
}

View file

@ -830,6 +830,7 @@ statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op)
0, // ex_state
0, // ex_bool
0, // ex_label
0, // ex_labelref
expr_block, // ex_block
expr_expr,
expr_uexpr,
@ -1107,6 +1108,7 @@ statement_slist (sblock_t *sblock, expr_t *e)
statement_state,
statement_bool,
statement_label,
0, // ex_labelref
statement_block,
statement_expr,
statement_uexpr,

View file

@ -327,18 +327,25 @@ build_switch (expr_t *sw, case_node_t *tree, int op, expr_t *sw_val,
} else {
int low = expr_integer (tree->low);
int high = expr_integer (tree->high);
symbol_t *sym;
expr_t *table;
const char *name = new_label_name ();
symbol_t *table_sym;
expr_t *table_expr;
expr_t *table_init;
const char *table_name = new_label_name ();
int i;
expr_t *range = binary_expr ('-', tree->high, tree->low);
range = fold_constants (range);
sym = make_symbol (name, array_type (&type_integer, high - low + 1),
pr.near_data, st_static);
table = new_symbol_expr (sym);
table = new_alias_expr (&type_integer, table);
table_init = new_block_expr ();
for (i = 0; i <= high - low; i++) {
tree->labels[i]->e.label.used++;
append_expr (table_init, address_expr (tree->labels[i], 0, 0));
}
table_sym = new_symbol (table_name);
initialize_def (table_sym, array_type (&type_integer, high - low + 1),
table_init, pr.near_data, st_static);
table_expr = new_symbol_expr (table_sym);
table_expr = new_alias_expr (&type_integer, table_expr);
if (tree->left) {
branch = branch_expr (IFB, temp, low_label);
@ -348,7 +355,7 @@ build_switch (expr_t *sw, case_node_t *tree, int op, expr_t *sw_val,
cast_expr (&type_uinteger, range));
branch = branch_expr ('i', test, high_label);
append_expr (sw, branch);
branch = new_binary_expr ('g', table, temp);
branch = new_binary_expr ('g', table_expr, temp);
append_expr (sw, branch);
if (tree->left) {
append_expr (sw, low_label);
@ -358,13 +365,6 @@ build_switch (expr_t *sw, case_node_t *tree, int op, expr_t *sw_val,
append_expr (sw, high_label);
build_switch (sw, tree->right, op, sw_val, temp, default_label);
}
for (i = 0; i <= high - low; i++) {
def_t loc;
loc.space = sym->s.def->space;
loc.offset = sym->s.def->offset + i;
tree->labels[i]->e.label.used++;
reloc_def_op (&tree->labels[i]->e.label, &loc);
}
}
}